@vltpkg/graph 0.0.0-9 → 1.0.0-rc.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.
Files changed (177) hide show
  1. package/README.md +136 -1
  2. package/dist/esm/actual/load.d.ts +49 -3
  3. package/dist/esm/actual/load.d.ts.map +1 -1
  4. package/dist/esm/actual/load.js +124 -73
  5. package/dist/esm/actual/load.js.map +1 -1
  6. package/dist/esm/browser.d.ts +8 -4
  7. package/dist/esm/browser.d.ts.map +1 -1
  8. package/dist/esm/browser.js +6 -2
  9. package/dist/esm/browser.js.map +1 -1
  10. package/dist/esm/build.d.ts +29 -0
  11. package/dist/esm/build.d.ts.map +1 -0
  12. package/dist/esm/build.js +79 -0
  13. package/dist/esm/build.js.map +1 -0
  14. package/dist/esm/dependencies.d.ts +10 -3
  15. package/dist/esm/dependencies.d.ts.map +1 -1
  16. package/dist/esm/dependencies.js +63 -0
  17. package/dist/esm/dependencies.js.map +1 -1
  18. package/dist/esm/diff.d.ts +67 -0
  19. package/dist/esm/diff.d.ts.map +1 -1
  20. package/dist/esm/diff.js +25 -0
  21. package/dist/esm/diff.js.map +1 -1
  22. package/dist/esm/edge.d.ts +7 -2
  23. package/dist/esm/edge.d.ts.map +1 -1
  24. package/dist/esm/edge.js +8 -0
  25. package/dist/esm/edge.js.map +1 -1
  26. package/dist/esm/graph.d.ts +20 -10
  27. package/dist/esm/graph.d.ts.map +1 -1
  28. package/dist/esm/graph.js +124 -21
  29. package/dist/esm/graph.js.map +1 -1
  30. package/dist/esm/ideal/add-nodes.d.ts +17 -2
  31. package/dist/esm/ideal/add-nodes.d.ts.map +1 -1
  32. package/dist/esm/ideal/add-nodes.js +9 -2
  33. package/dist/esm/ideal/add-nodes.js.map +1 -1
  34. package/dist/esm/ideal/append-nodes.d.ts +11 -1
  35. package/dist/esm/ideal/append-nodes.d.ts.map +1 -1
  36. package/dist/esm/ideal/append-nodes.js +176 -31
  37. package/dist/esm/ideal/append-nodes.js.map +1 -1
  38. package/dist/esm/ideal/build-ideal-from-starting-graph.d.ts.map +1 -1
  39. package/dist/esm/ideal/build-ideal-from-starting-graph.js +9 -5
  40. package/dist/esm/ideal/build-ideal-from-starting-graph.js.map +1 -1
  41. package/dist/esm/ideal/build.d.ts +9 -0
  42. package/dist/esm/ideal/build.d.ts.map +1 -1
  43. package/dist/esm/ideal/build.js +4 -1
  44. package/dist/esm/ideal/build.js.map +1 -1
  45. package/dist/esm/ideal/get-importer-specs.d.ts +3 -2
  46. package/dist/esm/ideal/get-importer-specs.d.ts.map +1 -1
  47. package/dist/esm/ideal/get-importer-specs.js +7 -5
  48. package/dist/esm/ideal/get-importer-specs.js.map +1 -1
  49. package/dist/esm/index.d.ts +8 -4
  50. package/dist/esm/index.d.ts.map +1 -1
  51. package/dist/esm/index.js +4 -1
  52. package/dist/esm/index.js.map +1 -1
  53. package/dist/esm/install.d.ts +8 -3
  54. package/dist/esm/install.d.ts.map +1 -1
  55. package/dist/esm/install.js +167 -20
  56. package/dist/esm/install.js.map +1 -1
  57. package/dist/esm/lockfile/load-edges.d.ts +8 -1
  58. package/dist/esm/lockfile/load-edges.d.ts.map +1 -1
  59. package/dist/esm/lockfile/load-edges.js +79 -15
  60. package/dist/esm/lockfile/load-edges.js.map +1 -1
  61. package/dist/esm/lockfile/load-nodes.d.ts +3 -2
  62. package/dist/esm/lockfile/load-nodes.d.ts.map +1 -1
  63. package/dist/esm/lockfile/load-nodes.js +72 -12
  64. package/dist/esm/lockfile/load-nodes.js.map +1 -1
  65. package/dist/esm/lockfile/load.d.ts +18 -5
  66. package/dist/esm/lockfile/load.d.ts.map +1 -1
  67. package/dist/esm/lockfile/load.js +53 -22
  68. package/dist/esm/lockfile/load.js.map +1 -1
  69. package/dist/esm/lockfile/save.d.ts +12 -3
  70. package/dist/esm/lockfile/save.d.ts.map +1 -1
  71. package/dist/esm/lockfile/save.js +49 -16
  72. package/dist/esm/lockfile/save.js.map +1 -1
  73. package/dist/esm/lockfile/types.d.ts +34 -4
  74. package/dist/esm/lockfile/types.d.ts.map +1 -1
  75. package/dist/esm/lockfile/types.js +31 -0
  76. package/dist/esm/lockfile/types.js.map +1 -1
  77. package/dist/esm/modifiers.d.ts +189 -0
  78. package/dist/esm/modifiers.d.ts.map +1 -0
  79. package/dist/esm/modifiers.js +330 -0
  80. package/dist/esm/modifiers.js.map +1 -0
  81. package/dist/esm/node.d.ts +77 -6
  82. package/dist/esm/node.d.ts.map +1 -1
  83. package/dist/esm/node.js +98 -5
  84. package/dist/esm/node.js.map +1 -1
  85. package/dist/esm/reify/add-edge.d.ts +1 -2
  86. package/dist/esm/reify/add-edge.d.ts.map +1 -1
  87. package/dist/esm/reify/add-edge.js +29 -18
  88. package/dist/esm/reify/add-edge.js.map +1 -1
  89. package/dist/esm/reify/add-edges.d.ts +1 -2
  90. package/dist/esm/reify/add-edges.d.ts.map +1 -1
  91. package/dist/esm/reify/add-edges.js +2 -3
  92. package/dist/esm/reify/add-edges.js.map +1 -1
  93. package/dist/esm/reify/add-nodes.d.ts.map +1 -1
  94. package/dist/esm/reify/add-nodes.js +4 -27
  95. package/dist/esm/reify/add-nodes.js.map +1 -1
  96. package/dist/esm/reify/bin-chmod.d.ts +11 -0
  97. package/dist/esm/reify/bin-chmod.d.ts.map +1 -0
  98. package/dist/esm/reify/bin-chmod.js +39 -0
  99. package/dist/esm/reify/bin-chmod.js.map +1 -0
  100. package/dist/esm/reify/build.d.ts +10 -1
  101. package/dist/esm/reify/build.d.ts.map +1 -1
  102. package/dist/esm/reify/build.js +36 -23
  103. package/dist/esm/reify/build.js.map +1 -1
  104. package/dist/esm/reify/calculate-save-value.d.ts +3 -0
  105. package/dist/esm/reify/calculate-save-value.d.ts.map +1 -0
  106. package/dist/esm/reify/calculate-save-value.js +45 -0
  107. package/dist/esm/reify/calculate-save-value.js.map +1 -0
  108. package/dist/esm/reify/check-needed-build.d.ts +25 -0
  109. package/dist/esm/reify/check-needed-build.d.ts.map +1 -0
  110. package/dist/esm/reify/check-needed-build.js +50 -0
  111. package/dist/esm/reify/check-needed-build.js.map +1 -0
  112. package/dist/esm/reify/delete-edge.d.ts.map +1 -1
  113. package/dist/esm/reify/delete-edge.js +3 -4
  114. package/dist/esm/reify/delete-edge.js.map +1 -1
  115. package/dist/esm/reify/extract-node.d.ts +24 -0
  116. package/dist/esm/reify/extract-node.d.ts.map +1 -0
  117. package/dist/esm/reify/extract-node.js +76 -0
  118. package/dist/esm/reify/extract-node.js.map +1 -0
  119. package/dist/esm/reify/index.d.ts +18 -1
  120. package/dist/esm/reify/index.d.ts.map +1 -1
  121. package/dist/esm/reify/index.js +84 -14
  122. package/dist/esm/reify/index.js.map +1 -1
  123. package/dist/esm/reify/internal-hoist.d.ts +9 -0
  124. package/dist/esm/reify/internal-hoist.d.ts.map +1 -0
  125. package/dist/esm/reify/internal-hoist.js +134 -0
  126. package/dist/esm/reify/internal-hoist.js.map +1 -0
  127. package/dist/esm/reify/update-importers-package-json.d.ts.map +1 -1
  128. package/dist/esm/reify/update-importers-package-json.js +15 -9
  129. package/dist/esm/reify/update-importers-package-json.js.map +1 -1
  130. package/dist/esm/remove-optional-subgraph.js +1 -1
  131. package/dist/esm/remove-optional-subgraph.js.map +1 -1
  132. package/dist/esm/resolve-save-type.d.ts +1 -2
  133. package/dist/esm/resolve-save-type.d.ts.map +1 -1
  134. package/dist/esm/resolve-save-type.js.map +1 -1
  135. package/dist/esm/stringify-node.d.ts +1 -1
  136. package/dist/esm/stringify-node.d.ts.map +1 -1
  137. package/dist/esm/stringify-node.js.map +1 -1
  138. package/dist/esm/transfer-data/load.d.ts +44 -0
  139. package/dist/esm/transfer-data/load.d.ts.map +1 -0
  140. package/dist/esm/transfer-data/load.js +176 -0
  141. package/dist/esm/transfer-data/load.js.map +1 -0
  142. package/dist/esm/uninstall.d.ts +5 -4
  143. package/dist/esm/uninstall.d.ts.map +1 -1
  144. package/dist/esm/uninstall.js +51 -19
  145. package/dist/esm/uninstall.js.map +1 -1
  146. package/dist/esm/update.d.ts +13 -0
  147. package/dist/esm/update.d.ts.map +1 -0
  148. package/dist/esm/update.js +63 -0
  149. package/dist/esm/update.js.map +1 -0
  150. package/dist/esm/virtual-root.d.ts +16 -0
  151. package/dist/esm/virtual-root.d.ts.map +1 -0
  152. package/dist/esm/virtual-root.js +79 -0
  153. package/dist/esm/virtual-root.js.map +1 -0
  154. package/dist/esm/visualization/human-readable-output.d.ts +4 -5
  155. package/dist/esm/visualization/human-readable-output.d.ts.map +1 -1
  156. package/dist/esm/visualization/human-readable-output.js +41 -18
  157. package/dist/esm/visualization/human-readable-output.js.map +1 -1
  158. package/dist/esm/visualization/json-output.d.ts +7 -3
  159. package/dist/esm/visualization/json-output.d.ts.map +1 -1
  160. package/dist/esm/visualization/json-output.js +35 -12
  161. package/dist/esm/visualization/json-output.js.map +1 -1
  162. package/dist/esm/visualization/mermaid-output.d.ts +7 -1
  163. package/dist/esm/visualization/mermaid-output.d.ts.map +1 -1
  164. package/dist/esm/visualization/mermaid-output.js +64 -9
  165. package/dist/esm/visualization/mermaid-output.js.map +1 -1
  166. package/dist/esm/visualization/object-like-output.d.ts +1 -1
  167. package/dist/esm/visualization/object-like-output.d.ts.map +1 -1
  168. package/dist/esm/visualization/object-like-output.js.map +1 -1
  169. package/package.json +30 -24
  170. package/dist/esm/reify/bin-paths.d.ts +0 -4
  171. package/dist/esm/reify/bin-paths.d.ts.map +0 -1
  172. package/dist/esm/reify/bin-paths.js +0 -23
  173. package/dist/esm/reify/bin-paths.js.map +0 -1
  174. package/dist/esm/types.d.ts +0 -42
  175. package/dist/esm/types.d.ts.map +0 -1
  176. package/dist/esm/types.js +0 -2
  177. package/dist/esm/types.js.map +0 -1
package/README.md CHANGED
@@ -5,7 +5,44 @@
5
5
  This is the graph library responsible for representing the packages
6
6
  that are involved in a given install.
7
7
 
8
- **[API](#api)** · **[Usage](#usage)**
8
+ **[Overview](#overview)** · **[Concepts](#concepts)** ·
9
+ **[Architecture](#architecture)** · **[API](#api)** ·
10
+ **[Usage](#usage)** · **[Related Workspaces](#related-workspaces)** ·
11
+ **[References](#references)**
12
+
13
+ ## Overview
14
+
15
+ The `@vltpkg/graph` workspace models a project's dependency
16
+ relationships and drives npm-compatible installs by computing how
17
+ `node_modules` should be structured. It exposes a public API through
18
+ `src/index.ts` that re-exports core types and workflows.
19
+
20
+ At a glance:
21
+
22
+ - `Graph` encapsulates the full dependency graph for a project
23
+ (including monorepo workspaces), and is the source of truth for how
24
+ to lay out `node_modules`.
25
+ - `Node` represents a unique package instance (uniqueness provided by
26
+ `@vltpkg/dep-id`).
27
+ - `Edge` represents a dependency relationship from a dependent to a
28
+ dependency (eg. `dependencies`, `devDependencies`,
29
+ `peerDependencies`, etc.).
30
+ - `Diff` describes the minimal set of changes required to transform an
31
+ Actual graph (disk) into an Ideal graph (desired outcome), which is
32
+ then applied by the `reify` subsystem.
33
+
34
+ ## Concepts
35
+
36
+ - Importers: Root-level nodes used as starting points of the graph.
37
+ The `mainImporter` is the project root (its `package.json`), and the
38
+ remaining importers are workspaces discovered by
39
+ `@vltpkg/workspaces`.
40
+ - Hidden Lockfile: A performance optimization stored at
41
+ `node_modules/.vlt-lock.json` mirroring the current on-disk state to
42
+ accelerate subsequent loads of the Actual graph.
43
+ - Modifiers: Configuration for selectively altering dependency
44
+ resolution; Ideal/Actual builders support skipping node loads when
45
+ modifiers change.
9
46
 
10
47
  ## API
11
48
 
@@ -26,6 +63,13 @@ local file system.
26
63
 
27
64
  Loads the lockfile file found at `projectRoot` and returns the graph.
28
65
 
66
+ ### `reify(options): Promise<Diff>`
67
+
68
+ Computes a `Diff` between the Actual and Ideal graphs and applies the
69
+ minimal filesystem changes (creating/deleting links, writing
70
+ lockfiles, hoisting, lifecycle scripts) to make the on-disk install
71
+ match the Ideal graph.
72
+
29
73
  ## Usage
30
74
 
31
75
  Here's a quick example of how to use the `@vltpkg/graph.ideal.build`
@@ -37,3 +81,94 @@ import { ideal } from '@vltpkg/graph'
37
81
 
38
82
  const graph = await ideal.build({ projectRoot: process.cwd() })
39
83
  ```
84
+
85
+ ### Load Actual Graph and Reify
86
+
87
+ ```ts
88
+ import { actual, ideal, reify } from '@vltpkg/graph'
89
+
90
+ // Load current on-disk state
91
+ const from = actual.load({
92
+ projectRoot: process.cwd(),
93
+ packageJson,
94
+ scurry,
95
+ })
96
+
97
+ // Build intended end state (may start from lockfile or actual)
98
+ const to = await ideal.build({
99
+ projectRoot: process.cwd(),
100
+ packageInfo,
101
+ packageJson,
102
+ scurry,
103
+ })
104
+
105
+ // Apply minimal changes to match Ideal
106
+ await reify({
107
+ graph: to,
108
+ actual: from,
109
+ packageInfo,
110
+ packageJson,
111
+ scurry,
112
+ })
113
+ ```
114
+
115
+ ### Working With Lockfiles
116
+
117
+ ```ts
118
+ import { lockfile } from '@vltpkg/graph'
119
+
120
+ // Load virtual graph from vlt-lock.json
121
+ const g = lockfile.load({
122
+ projectRoot,
123
+ mainManifest,
124
+ packageJson,
125
+ scurry,
126
+ })
127
+
128
+ // Save both lockfile formats
129
+ lockfile.save({ graph: g, projectRoot, packageJson, scurry })
130
+ ```
131
+
132
+ ## Architecture
133
+
134
+ Graph construction modes supported by the library:
135
+
136
+ - Virtual Graphs (lockfile-based)
137
+ - Load and save via `src/lockfile/load.ts` and
138
+ `src/lockfile/save.ts`
139
+ - Hidden lockfile: `node_modules/.vlt-lock.json` for faster loads
140
+
141
+ - Actual Graphs (filesystem-based)
142
+ - Loaded by traversing `node_modules` via `src/actual/load.ts`
143
+ - May shortcut to Hidden Lockfile if present and valid
144
+ - File layout changes are performed by `src/reify/`
145
+
146
+ - Ideal Graphs (desired end state)
147
+ - Entry: `src/ideal/build.ts`
148
+ - Starts from Virtual (preferred) or falls back to Actual
149
+ - Merges `add`/`remove` input with importer manifests using
150
+ `src/ideal/get-importer-specs.ts`
151
+ - Fetches and expands manifests using `@vltpkg/package-info`, reuses
152
+ existing nodes that satisfy specs
153
+
154
+ Finally, `src/diff.ts` computes changes and `src/reify/` applies them
155
+ to the filesystem.
156
+
157
+ ## Related Workspaces
158
+
159
+ - `@vltpkg/dep-id`: Unique IDs for packages, ensuring `Node` identity
160
+ - `@vltpkg/spec`: Parse/normalize dependency specifiers and registry
161
+ semantics
162
+ - `@vltpkg/semver`: Semantic version parsing/comparison
163
+ - `@vltpkg/package-info`: Fetch remote manifests and artifacts
164
+ (registry, git, tarball)
165
+ - `@vltpkg/package-json`: Read and cache local `package.json` files
166
+ - `@vltpkg/workspaces`: Monorepo workspace discovery and grouping
167
+
168
+ ## References
169
+
170
+ - package.json format and behavior:
171
+ [https://docs.npmjs.com/cli/v11/configuring-npm/package-json](https://docs.npmjs.com/cli/v11/configuring-npm/package-json)
172
+ - Semantic Versioning:
173
+ [https://semver.org/spec/v2.0.0.html](https://semver.org/spec/v2.0.0.html)
174
+ - Monorepos: [https://monorepo.tools](https://monorepo.tools)
@@ -1,9 +1,12 @@
1
+ import { Spec } from '@vltpkg/spec';
2
+ import { Graph } from '../graph.ts';
3
+ import type { DepID } from '@vltpkg/dep-id';
1
4
  import type { PackageJson } from '@vltpkg/package-json';
2
5
  import type { SpecOptions } from '@vltpkg/spec';
3
- import type { Manifest } from '@vltpkg/types';
6
+ import type { NormalizedManifest } from '@vltpkg/types';
4
7
  import type { Monorepo } from '@vltpkg/workspaces';
5
8
  import type { Path, PathScurry } from 'path-scurry';
6
- import { Graph } from '../graph.ts';
9
+ import type { GraphModifier } from '../modifiers.ts';
7
10
  export type LoadOptions = SpecOptions & {
8
11
  /**
9
12
  * The project root dirname.
@@ -12,7 +15,11 @@ export type LoadOptions = SpecOptions & {
12
15
  /**
13
16
  * The project root manifest.
14
17
  */
15
- mainManifest?: Manifest;
18
+ mainManifest?: NormalizedManifest;
19
+ /**
20
+ * The graph modifiers helper object.
21
+ */
22
+ modifiers?: GraphModifier;
16
23
  /**
17
24
  * A {@link Monorepo} object, for managing workspaces
18
25
  */
@@ -39,12 +46,51 @@ export type LoadOptions = SpecOptions & {
39
46
  * hidden lockfile at `node_modules/.vlt-lock.json`
40
47
  */
41
48
  skipHiddenLockfile?: boolean;
49
+ /**
50
+ * Load only importers into the graph if the modifiers have changed.
51
+ */
52
+ skipLoadingNodesOnModifiersChange?: boolean;
53
+ /**
54
+ * If set to `true`, fail if lockfile is missing or out of date.
55
+ * Used by ci command to enforce lockfile integrity.
56
+ */
57
+ expectLockfile?: boolean;
58
+ /**
59
+ * If set to `true`, fail if lockfile is missing or out of sync with package.json.
60
+ * Prevents any lockfile modifications and is stricter than expectLockfile.
61
+ */
62
+ frozenLockfile?: boolean;
63
+ /**
64
+ * If set to `true`, only update the lockfile without performing any node_modules
65
+ * operations. Skips package extraction, filesystem operations, and hidden lockfile saves.
66
+ */
67
+ lockfileOnly?: boolean;
42
68
  };
43
69
  export type ReadEntry = {
44
70
  alias: string;
45
71
  name: string;
46
72
  realpath: Path;
47
73
  };
74
+ /**
75
+ * The configuration object type as it is saved in the `.vlt/vlt.json`
76
+ */
77
+ export type StoreConfigObject = {
78
+ modifiers: Record<string, string> | undefined;
79
+ };
80
+ /**
81
+ * Checks if a given object is a {@link StoreConfigObject}.
82
+ */
83
+ export declare const isStoreConfigObject: (obj: unknown) => obj is StoreConfigObject;
84
+ /**
85
+ * Returns a {@link StoreConfigObject} from a given object.
86
+ * Throws a TypeError if the object can't be converted.
87
+ */
88
+ export declare const asStoreConfigObject: (obj: unknown) => StoreConfigObject;
89
+ /**
90
+ * Returns a {@link DepID} for a given spec and path, if the spec is
91
+ * path-based or a registry spec, otherwise returns `undefined`.
92
+ */
93
+ export declare const getPathBasedId: (spec: Spec, path: Path) => DepID | undefined;
48
94
  /**
49
95
  * Read the file system looking for `node_modules` folders and
50
96
  * returns a new {@link Graph} that represents the relationship
@@ -1 +1 @@
1
- {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../../src/actual/load.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAEvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAGnD,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAKnC,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG;IACtC;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,QAAQ,CAAA;IACvB;;OAEG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB;;OAEG;IACH,WAAW,EAAE,WAAW,CAAA;IACxB;;OAEG;IACH,MAAM,EAAE,UAAU,CAAA;IAClB;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,IAAI,CAAA;CACf,CAAA;AA6QD;;;;GAIG;AACH,eAAO,MAAM,IAAI,YAAa,WAAW,KAAG,KAwD3C,CAAA"}
1
+ {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../../src/actual/load.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAQnC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAEnC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAEnD,OAAO,KAAK,EACV,aAAa,EAEd,MAAM,iBAAiB,CAAA;AAGxB,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG;IACtC;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAA;IACjC;;OAEG;IACH,SAAS,CAAC,EAAE,aAAa,CAAA;IACzB;;OAEG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB;;OAEG;IACH,WAAW,EAAE,WAAW,CAAA;IACxB;;OAEG;IACH,MAAM,EAAE,UAAU,CAAA;IAClB;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B;;OAEG;IACH,iCAAiC,CAAC,EAAE,OAAO,CAAA;IAE3C;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,IAAI,CAAA;CACf,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;CAC9C,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,QACzB,OAAO,KACX,GAAG,IAAI,iBAGe,CAAA;AAEzB;;;GAGG;AACH,eAAO,MAAM,mBAAmB,QACzB,OAAO,KACX,iBAKF,CAAA;AAUD;;;GAGG;AACH,eAAO,MAAM,cAAc,SACnB,IAAI,QACJ,IAAI,KACT,KAAK,GAAG,SAGQ,CAAA;AA2RnB;;;;GAIG;AACH,eAAO,MAAM,IAAI,YAAa,WAAW,KAAG,KA4F3C,CAAA"}
@@ -1,15 +1,39 @@
1
1
  import { asDepID, hydrate, joinDepIDTuple } from '@vltpkg/dep-id';
2
2
  import { Spec } from '@vltpkg/spec';
3
- import { longDependencyTypes } from '@vltpkg/types';
4
- import { shorten } from "../dependencies.js";
3
+ import { graphStep } from '@vltpkg/output';
4
+ import { isObject } from '@vltpkg/types';
5
+ import { shorten, getRawDependencies, getDependencies, } from "../dependencies.js";
5
6
  import { Graph } from "../graph.js";
6
7
  import { loadHidden } from "../lockfile/load.js";
7
- import { graphStep } from '@vltpkg/output';
8
+ import { readFileSync } from 'node:fs';
9
+ /**
10
+ * Checks if a given object is a {@link StoreConfigObject}.
11
+ */
12
+ export const isStoreConfigObject = (obj) => isObject(obj) &&
13
+ Object.prototype.hasOwnProperty.call(obj, 'modifiers') &&
14
+ isObject(obj.modifiers);
15
+ /**
16
+ * Returns a {@link StoreConfigObject} from a given object.
17
+ * Throws a TypeError if the object can't be converted.
18
+ */
19
+ export const asStoreConfigObject = (obj) => {
20
+ if (!isStoreConfigObject(obj)) {
21
+ throw new TypeError(`Expected a store config object, got ${obj}`);
22
+ }
23
+ return obj;
24
+ };
25
+ // path-based refer to the types of dependencies that are directly linked to
26
+ // their real location in the file system and thus will not have an entry
27
+ // in the `node_modules/.vlt` store
8
28
  const pathBasedType = new Set(['file', 'workspace']);
9
29
  const isPathBasedType = (type) => pathBasedType.has(type);
10
- const getPathBasedId = (spec, path) => isPathBasedType(spec.type) ?
11
- joinDepIDTuple([spec.type, path])
12
- : undefined;
30
+ /**
31
+ * Returns a {@link DepID} for a given spec and path, if the spec is
32
+ * path-based or a registry spec, otherwise returns `undefined`.
33
+ */
34
+ export const getPathBasedId = (spec, path) => isPathBasedType(spec.type) ?
35
+ joinDepIDTuple([spec.type, path.relativePosix()])
36
+ : findDepID(path);
13
37
  /**
14
38
  * Retrieve the {@link DepID} for a given package from its location.
15
39
  */
@@ -26,47 +50,25 @@ const findNodeModules = ({ parent, name, isCWD, }) => parent?.name === 'node_mod
26
50
  * Retrieves the scoped-normalized package name from its {@link Path}.
27
51
  */
28
52
  const findName = ({ parent, name }) => parent?.name.startsWith('@') ? `${parent.name}/${name}` : name;
29
- const isStringArray = (a) => Array.isArray(a) && !a.some(b => typeof b !== 'string');
30
- /*
31
- * Retrieves a map of all dependencies, of all types, that can be iterated
32
- * on and consulted when parsing the directory contents of the current node.
53
+ /**
54
+ * Helper function that gets a modified {@link Spec} when finding a modifier
55
+ * that applies to a given dependency. Otherwise returns the original spec
56
+ * value and no queryModifier.
33
57
  */
34
- const getDeps = (node) => {
35
- const dependencies = new Map();
36
- const bundleDeps = node.manifest?.bundleDependencies ?? [];
37
- // if it's an importer, bundleDeps are just normal. if it's a dep,
38
- // then they're ignored entirely.
39
- const bundled = (!node.importer &&
40
- !node.id.startsWith('git') &&
41
- isStringArray(bundleDeps)) ?
42
- new Set(bundleDeps)
43
- : new Set();
44
- for (const depType of longDependencyTypes) {
45
- const obj = node.manifest?.[depType];
46
- // only care about devDeps for importers and git or symlink deps
47
- // technically this will also include devDeps for tarball file: specs,
48
- // but that is likely rare enough to not worry about too much.
49
- if (depType === 'devDependencies' &&
50
- !node.importer &&
51
- !node.id.startsWith('git') &&
52
- !node.id.startsWith('file')) {
53
- continue;
54
- }
55
- if (obj) {
56
- for (const [name, bareSpec] of Object.entries(obj)) {
57
- // if it's a bundled dependency, we just ignore it entirely.
58
- if (bundled.has(name))
59
- continue;
60
- dependencies.set(name, {
61
- name,
62
- type: depType,
63
- bareSpec,
64
- registry: node.registry,
65
- });
66
- }
67
- }
58
+ const maybeApplyModifierToSpec = (spec, depName, modifierRefs) => {
59
+ const activeModifier = modifierRefs?.get(depName);
60
+ const queryModifier = activeModifier?.modifier.query;
61
+ const completeModifier = activeModifier &&
62
+ activeModifier.interactiveBreadcrumb.current ===
63
+ activeModifier.modifier.breadcrumb.last;
64
+ if (queryModifier &&
65
+ completeModifier &&
66
+ 'spec' in activeModifier.modifier) {
67
+ const modifiedSpec = activeModifier.modifier.spec;
68
+ modifiedSpec.overridden = true;
69
+ return { spec: modifiedSpec, queryModifier };
68
70
  }
69
- return dependencies;
71
+ return { spec, queryModifier };
70
72
  };
71
73
  /**
72
74
  * Reads the current directory defined at `currDir` and looks for folder
@@ -115,10 +117,14 @@ const readDir = (scurry, currDir, fromNodeName) => {
115
117
  * as dependencies of `fromNode`, building the instantiated `graph`.
116
118
  */
117
119
  const parseDir = (options, scurry, packageJson, depsFound, graph, fromNode, currDir) => {
118
- const { loadManifests } = options;
119
- const dependencies = getDeps(fromNode);
120
+ const { loadManifests, modifiers } = options;
121
+ const dependencies = getRawDependencies(fromNode);
120
122
  const seenDeps = new Set();
121
123
  const readItems = readDir(scurry, currDir, fromNode.name);
124
+ // Get modifier references for this node's dependencies
125
+ const modifierRefs = modifiers?.tryDependencies(fromNode, [
126
+ ...getDependencies(fromNode, options).values(),
127
+ ]);
122
128
  for (const { alias, name, realpath } of readItems) {
123
129
  let node;
124
130
  // tracks what dependencies have been seen
@@ -129,10 +135,15 @@ const parseDir = (options, scurry, packageJson, depsFound, graph, fromNode, curr
129
135
  if (!loadManifests) {
130
136
  const depId = findDepID(realpath);
131
137
  if (depId) {
132
- const h = hydrate(depId, alias, {
138
+ let h = hydrate(depId, alias, {
133
139
  ...options,
134
- registry: fromNode.registry,
135
140
  });
141
+ // if the parsed registry value is using the default value, then
142
+ // the node should inherit the registry value from its parent node
143
+ h.inheritedRegistry = fromNode.registry;
144
+ // Check for active modifiers and replace spec even when not loading manifests
145
+ const { spec: modifiedSpec, queryModifier } = maybeApplyModifierToSpec(h, alias, modifierRefs);
146
+ h = modifiedSpec;
136
147
  // graphs build with no manifest have no notion of
137
148
  // dependency types and or spec definitions since those
138
149
  // would have to be parsed from a manifest
@@ -140,10 +151,12 @@ const parseDir = (options, scurry, packageJson, depsFound, graph, fromNode, curr
140
151
  h, // uses spec from hydrated id
141
152
  {
142
153
  name,
143
- ...(h.registrySpec ?
144
- { version: h.registrySpec } // adds version if available
145
- : null),
146
- }, depId);
154
+ }, depId, queryModifier);
155
+ // Update active entry after placing package
156
+ const activeModifier = modifierRefs?.get(alias);
157
+ if (activeModifier && node) {
158
+ modifiers?.updateActiveEntry(node, activeModifier);
159
+ }
147
160
  }
148
161
  }
149
162
  // retrieve references to the current folder name found in `fromNode`
@@ -161,12 +174,22 @@ const parseDir = (options, scurry, packageJson, depsFound, graph, fromNode, curr
161
174
  const type = deps?.type || 'dependencies';
162
175
  const bareSpec = deps?.bareSpec || '*';
163
176
  const depType = shorten(type, alias, fromNode.manifest);
164
- const spec = Spec.parse(alias, bareSpec, {
177
+ let spec = Spec.parse(alias, bareSpec, {
165
178
  ...options,
166
- registry: fromNode.registry,
167
179
  });
168
- const maybeId = getPathBasedId(spec, realpath.relativePosix());
169
- node = graph.placePackage(fromNode, depType, spec, mani, maybeId);
180
+ // if the parsed registry value is using the default value, then
181
+ // the node should inherit the registry value from its parent node
182
+ spec.inheritedRegistry = fromNode.registry;
183
+ // Check for active modifiers and replace spec if a modifier is complete
184
+ const { spec: modifiedSpec, queryModifier } = maybeApplyModifierToSpec(spec, alias, modifierRefs);
185
+ spec = modifiedSpec;
186
+ const maybeId = getPathBasedId(spec, realpath);
187
+ node = graph.placePackage(fromNode, depType, spec, mani, maybeId, queryModifier);
188
+ // Update active entry after placing package
189
+ const activeModifier = modifierRefs?.get(alias);
190
+ if (activeModifier && node) {
191
+ modifiers?.updateActiveEntry(node, activeModifier);
192
+ }
170
193
  }
171
194
  if (node) {
172
195
  // If a found dependency is not declared in any of the original
@@ -197,11 +220,16 @@ const parseDir = (options, scurry, packageJson, depsFound, graph, fromNode, curr
197
220
  for (const { name, type, bareSpec } of dependencies.values()) {
198
221
  if (!seenDeps.has(name)) {
199
222
  const depType = shorten(type, name, fromNode.manifest);
200
- const spec = Spec.parse(name, bareSpec, {
223
+ let spec = Spec.parse(name, bareSpec, {
201
224
  ...options,
202
- registry: fromNode.registry,
203
225
  });
204
- graph.placePackage(fromNode, depType, spec);
226
+ // if the parsed registry value is using the default value, then
227
+ // the node should inherit the registry value from its parent node
228
+ spec.inheritedRegistry = fromNode.registry;
229
+ // Check for active modifiers and replace spec for missing dependencies
230
+ const { spec: modifiedSpec, queryModifier } = maybeApplyModifierToSpec(spec, name, modifierRefs);
231
+ spec = modifiedSpec;
232
+ graph.placePackage(fromNode, depType, spec, undefined, undefined, queryModifier);
205
233
  }
206
234
  }
207
235
  };
@@ -212,34 +240,57 @@ const parseDir = (options, scurry, packageJson, depsFound, graph, fromNode, curr
212
240
  */
213
241
  export const load = (options) => {
214
242
  const done = graphStep('actual');
215
- // TODO: once hidden lockfile is more reliable, default to false here
216
- const { skipHiddenLockfile = true, projectRoot, packageJson, scurry, monorepo, } = options;
243
+ const { modifiers, monorepo, projectRoot, packageJson, scurry, skipHiddenLockfile = false, skipLoadingNodesOnModifiersChange = false, } = options;
217
244
  const mainManifest = options.mainManifest ?? packageJson.read(projectRoot);
218
245
  if (!skipHiddenLockfile) {
219
246
  try {
247
+ // if we reach here, the hidden lockfile is valid
220
248
  const graph = loadHidden({
249
+ ...options,
221
250
  projectRoot,
222
251
  mainManifest,
223
252
  packageJson,
224
253
  monorepo,
225
254
  scurry,
226
255
  });
227
- // TODO: check mtime of lockfile vs .vlt folder
256
+ done();
228
257
  return graph;
229
258
  }
230
- catch { }
259
+ catch {
260
+ // if validation fails or any other error occurs,
261
+ // fall back to filesystem traversal
262
+ }
231
263
  }
232
264
  const graph = new Graph({ ...options, mainManifest });
233
- const depsFound = new Map();
234
- // starts the list of initial folders to parse using the importer nodes
235
- for (const importer of graph.importers) {
236
- depsFound.set(importer, scurry.cwd.resolve(`${importer.location}/node_modules`));
265
+ // retrieve the configuration object from the store
266
+ let storeConfig = { modifiers: undefined };
267
+ try {
268
+ storeConfig = asStoreConfigObject(JSON.parse(readFileSync(scurry.resolve('node_modules/.vlt/vlt.json'), 'utf8')));
237
269
  }
238
- // breadth-first traversal of the file system tree reading deps found
239
- // starting from the node_modules folder of every importer in order to
240
- // find the actual installed dependencies at each location
241
- for (const [node, path] of depsFound.entries()) {
242
- parseDir(options, scurry, packageJson, depsFound, graph, node, path);
270
+ catch { }
271
+ const storeModifiers = JSON.stringify(storeConfig.modifiers ?? {});
272
+ const optionsModifiers = JSON.stringify(modifiers?.config);
273
+ const modifiersChanged = storeModifiers !== optionsModifiers;
274
+ const shouldLoadDependencies = !(skipLoadingNodesOnModifiersChange && modifiersChanged);
275
+ // will only skip loading dependencies if the
276
+ // skipLoadingNodesOnModifiersChange option is set to true
277
+ // and the current modifiers have not changed when compared
278
+ // to the modifiers stored in the `node_modules/.vlt/vlt.json` store config
279
+ if (shouldLoadDependencies) {
280
+ const depsFound = new Map();
281
+ // starts the list of initial folders to parse using the importer nodes
282
+ for (const importer of graph.importers) {
283
+ modifiers?.tryImporter(importer);
284
+ depsFound.set(importer, scurry.cwd.resolve(`${importer.location}/node_modules`));
285
+ }
286
+ // breadth-first traversal of the file system tree reading deps found
287
+ // starting from the node_modules folder of every importer in order to
288
+ // find the actual installed dependencies at each location
289
+ for (const [node, path] of depsFound.entries()) {
290
+ parseDir(options, scurry, packageJson, depsFound, graph, node, path);
291
+ }
292
+ // Clean up any pending modifier entries that were never completed
293
+ modifiers?.rollbackActiveEntries();
243
294
  }
244
295
  done();
245
296
  return graph;
@@ -1 +1 @@
1
- {"version":3,"file":"load.js","sourceRoot":"","sources":["../../../src/actual/load.ts"],"names":[],"mappings":"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","sourcesContent":["import { asDepID, hydrate, joinDepIDTuple } from '@vltpkg/dep-id'\nimport type { DepID } from '@vltpkg/dep-id'\nimport type { PackageJson } from '@vltpkg/package-json'\nimport { Spec } from '@vltpkg/spec'\nimport type { SpecOptions } from '@vltpkg/spec'\nimport { longDependencyTypes } from '@vltpkg/types'\nimport type { Manifest } from '@vltpkg/types'\nimport type { Monorepo } from '@vltpkg/workspaces'\nimport type { Path, PathScurry } from 'path-scurry'\nimport { shorten } from '../dependencies.ts'\nimport type { RawDependency } from '../dependencies.ts'\nimport { Graph } from '../graph.ts'\nimport { loadHidden } from '../lockfile/load.ts'\nimport type { Node } from '../node.ts'\nimport { graphStep } from '@vltpkg/output'\n\nexport type LoadOptions = SpecOptions & {\n /**\n * The project root dirname.\n */\n projectRoot: string\n /**\n * The project root manifest.\n */\n mainManifest?: Manifest\n /**\n * A {@link Monorepo} object, for managing workspaces\n */\n monorepo?: Monorepo\n /**\n * A {@link PackageJson} object, for sharing manifest caches\n */\n packageJson: PackageJson\n /**\n * A {@link PathScurry} object, for use in globs\n */\n scurry: PathScurry\n /**\n * If set to `false`, `actual.load` will not load any `package.json`\n * files while traversing the file system.\n *\n * The resulting {@link Graph} from loading with `loadManifests=false`\n * has no information on dependency types or the specs defined and\n * no information on missing and extraneous dependencies.\n */\n loadManifests?: boolean\n /**\n * If set to `true`, then do not shortcut the process by reading the\n * hidden lockfile at `node_modules/.vlt-lock.json`\n */\n skipHiddenLockfile?: boolean\n}\n\nexport type ReadEntry = {\n alias: string\n name: string\n realpath: Path\n}\n\nconst pathBasedType = new Set(['file', 'workspace'])\nconst isPathBasedType = (\n type: string,\n): type is 'file' | 'workspace' => pathBasedType.has(type)\nconst getPathBasedId = (\n spec: Spec,\n path: string,\n): DepID | undefined =>\n isPathBasedType(spec.type) ?\n joinDepIDTuple([spec.type, path])\n : undefined\n\n/**\n * Retrieve the {@link DepID} for a given package from its location.\n */\nconst findDepID = ({ parent, name }: Path): DepID | undefined =>\n parent?.name === '.vlt' ? asDepID(name)\n : parent?.isCWD === false ? findDepID(parent)\n : undefined\n\n/**\n * Retrieves the closest `node_modules` parent {@link Path} found.\n */\nconst findNodeModules = ({\n parent,\n name,\n isCWD,\n}: Path): Path | undefined =>\n parent?.name === 'node_modules' ? parent\n : parent && name !== '.vlt' && !isCWD ? findNodeModules(parent)\n : undefined\n\n/**\n * Retrieves the scoped-normalized package name from its {@link Path}.\n */\nconst findName = ({ parent, name }: Path): string =>\n parent?.name.startsWith('@') ? `${parent.name}/${name}` : name\n\nconst isStringArray = (a: unknown): a is string[] =>\n Array.isArray(a) && !a.some(b => typeof b !== 'string')\n\n/*\n * Retrieves a map of all dependencies, of all types, that can be iterated\n * on and consulted when parsing the directory contents of the current node.\n */\nconst getDeps = (node: Node) => {\n const dependencies = new Map<string, RawDependency>()\n const bundleDeps: unknown = node.manifest?.bundleDependencies ?? []\n // if it's an importer, bundleDeps are just normal. if it's a dep,\n // then they're ignored entirely.\n const bundled =\n (\n !node.importer &&\n !node.id.startsWith('git') &&\n isStringArray(bundleDeps)\n ) ?\n new Set(bundleDeps)\n : new Set<string>()\n for (const depType of longDependencyTypes) {\n const obj: Record<string, string> | undefined =\n node.manifest?.[depType]\n // only care about devDeps for importers and git or symlink deps\n // technically this will also include devDeps for tarball file: specs,\n // but that is likely rare enough to not worry about too much.\n if (\n depType === 'devDependencies' &&\n !node.importer &&\n !node.id.startsWith('git') &&\n !node.id.startsWith('file')\n ) {\n continue\n }\n if (obj) {\n for (const [name, bareSpec] of Object.entries(obj)) {\n // if it's a bundled dependency, we just ignore it entirely.\n if (bundled.has(name)) continue\n dependencies.set(name, {\n name,\n type: depType,\n bareSpec,\n registry: node.registry,\n })\n }\n }\n }\n return dependencies\n}\n\n/**\n * Reads the current directory defined at `currDir` and looks for folder\n * names and their realpath resolution, normalizing scoped package names\n * and removing any invalid symlinks from the list of items that should\n * be parsed through in order to build the graph.\n */\nconst readDir = (\n scurry: PathScurry,\n currDir: Path,\n fromNodeName?: string,\n) => {\n const res = new Set<ReadEntry>()\n for (const entry of scurry.readdirSync(currDir)) {\n // ignore any hidden files / folders\n if (entry.name.startsWith('.')) continue\n\n // scope folder found, it will need to be read and iterated over\n // in order to find any scoped packages inside\n if (entry.name.startsWith('@')) {\n const scopedItems = readDir(scurry, entry, fromNodeName)\n for (const scopedItem of scopedItems) {\n res.add(scopedItem)\n }\n continue\n }\n\n // skip anything that isn't a symlink, it's not an edge\n if (!entry.isSymbolicLink()) continue\n\n // we'll need to learn what is the real path for this entry in order\n // to retrieve the `location` and `id` properties for the node, if a\n // realpath is not found just move on to the next element\n const realpath = entry.realpathSync()\n if (!realpath) {\n continue\n }\n\n // infer both the alias and proper package names, including scopes\n const alias = findName(entry)\n const name = findName(realpath)\n res.add({\n alias,\n name,\n realpath,\n })\n }\n return res\n}\n\n/**\n * Parses the files located at `currDir` and place packages found inside\n * as dependencies of `fromNode`, building the instantiated `graph`.\n */\nconst parseDir = (\n options: LoadOptions,\n scurry: PathScurry,\n packageJson: PackageJson,\n depsFound: Map<Node, Path>,\n graph: Graph,\n fromNode: Node,\n currDir: Path,\n) => {\n const { loadManifests } = options\n const dependencies = getDeps(fromNode)\n const seenDeps = new Set<string>()\n const readItems: Set<ReadEntry> = readDir(\n scurry,\n currDir,\n fromNode.name,\n )\n\n for (const { alias, name, realpath } of readItems) {\n let node\n\n // tracks what dependencies have been seen\n // so that we can mark missing dependencies\n seenDeps.add(alias)\n\n // places the package in the graph reading\n // its manifest only if necessary\n if (!loadManifests) {\n const depId = findDepID(realpath)\n\n if (depId) {\n const h = hydrate(depId, alias, {\n ...options,\n registry: fromNode.registry,\n })\n\n // graphs build with no manifest have no notion of\n // dependency types and or spec definitions since those\n // would have to be parsed from a manifest\n node = graph.placePackage(\n fromNode,\n 'prod', // defaults to prod deps\n h, // uses spec from hydrated id\n {\n name,\n ...(h.registrySpec ?\n { version: h.registrySpec } // adds version if available\n : null),\n },\n depId,\n )\n }\n }\n\n // retrieve references to the current folder name found in `fromNode`\n // manifest listed dependencies, removing it from the map will leave\n // a list of missing dependencies at the end of the iteration\n const deps = dependencies.get(alias)\n\n // in case this graph is skipping manifests, this next block might\n // still need to execute, thus actually loading a manifest file, for\n // edge-cases such as loading a linked node that is not going to have\n // DepID info available in its realpath or extraneous nodes\n if (!node) {\n const mani = packageJson.read(realpath.fullpath())\n // declares fallback default values for both depType and bareSpec\n // in order to support loadManifests=false fallback for link nodes\n const type = deps?.type || 'dependencies'\n const bareSpec = deps?.bareSpec || '*'\n\n const depType = shorten(type, alias, fromNode.manifest)\n const spec = Spec.parse(alias, bareSpec, {\n ...options,\n registry: fromNode.registry,\n })\n const maybeId = getPathBasedId(spec, realpath.relativePosix())\n node = graph.placePackage(\n fromNode,\n depType,\n spec,\n mani,\n maybeId,\n )\n }\n\n if (node) {\n // If a found dependency is not declared in any of the original\n // node dependencies, then add an edge to the graph pointing to it\n // and mark it as extraneous.\n //\n // This only makes sense if full manifests are being loaded\n // so that we have reference to dependencies info.\n if (loadManifests && !deps) {\n const [edge] = node.edgesIn\n if (edge) {\n graph.extraneousDependencies.add(edge)\n }\n }\n\n // for a succesfully created node, add its location\n // property and queue up to read its dependencies\n node.location = `./${realpath.relativePosix()}`\n const node_modules = findNodeModules(realpath)\n\n // queue items up to continue parsing dirs in case a node was succesfully\n // placed in the graph and its node_modules folder was correctly found\n if (node_modules) {\n depsFound.set(node, node_modules)\n }\n }\n }\n\n // any remaining dependencies that have not been found\n // when reading the directory should be marked as missing\n for (const { name, type, bareSpec } of dependencies.values()) {\n if (!seenDeps.has(name)) {\n const depType = shorten(type, name, fromNode.manifest)\n const spec = Spec.parse(name, bareSpec, {\n ...options,\n registry: fromNode.registry,\n })\n graph.placePackage(fromNode, depType, spec)\n }\n }\n}\n\n/**\n * Read the file system looking for `node_modules` folders and\n * returns a new {@link Graph} that represents the relationship\n * between the dependencies found.\n */\nexport const load = (options: LoadOptions): Graph => {\n const done = graphStep('actual')\n // TODO: once hidden lockfile is more reliable, default to false here\n const {\n skipHiddenLockfile = true,\n projectRoot,\n packageJson,\n scurry,\n monorepo,\n } = options\n const mainManifest =\n options.mainManifest ?? packageJson.read(projectRoot)\n\n if (!skipHiddenLockfile) {\n try {\n const graph = loadHidden({\n projectRoot,\n mainManifest,\n packageJson,\n monorepo,\n scurry,\n })\n // TODO: check mtime of lockfile vs .vlt folder\n return graph\n } catch {}\n }\n\n const graph = new Graph({ ...options, mainManifest })\n const depsFound = new Map<Node, Path>()\n\n // starts the list of initial folders to parse using the importer nodes\n for (const importer of graph.importers) {\n depsFound.set(\n importer,\n scurry.cwd.resolve(`${importer.location}/node_modules`),\n )\n }\n\n // breadth-first traversal of the file system tree reading deps found\n // starting from the node_modules folder of every importer in order to\n // find the actual installed dependencies at each location\n for (const [node, path] of depsFound.entries()) {\n parseDir(\n options,\n scurry,\n packageJson,\n depsFound,\n graph,\n node,\n path,\n )\n }\n\n done()\n\n return graph\n}\n"]}
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../../../src/actual/load.ts"],"names":[],"mappings":"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","sourcesContent":["import { asDepID, hydrate, joinDepIDTuple } from '@vltpkg/dep-id'\nimport { Spec } from '@vltpkg/spec'\nimport { graphStep } from '@vltpkg/output'\nimport { isObject } from '@vltpkg/types'\nimport {\n shorten,\n getRawDependencies,\n getDependencies,\n} from '../dependencies.ts'\nimport { Graph } from '../graph.ts'\nimport { loadHidden } from '../lockfile/load.ts'\nimport type { DepID } from '@vltpkg/dep-id'\nimport type { PackageJson } from '@vltpkg/package-json'\nimport type { SpecOptions } from '@vltpkg/spec'\nimport type { NormalizedManifest } from '@vltpkg/types'\nimport type { Monorepo } from '@vltpkg/workspaces'\nimport type { Path, PathScurry } from 'path-scurry'\nimport type { Node } from '../node.ts'\nimport type {\n GraphModifier,\n ModifierActiveEntry,\n} from '../modifiers.ts'\nimport { readFileSync } from 'node:fs'\n\nexport type LoadOptions = SpecOptions & {\n /**\n * The project root dirname.\n */\n projectRoot: string\n /**\n * The project root manifest.\n */\n mainManifest?: NormalizedManifest\n /**\n * The graph modifiers helper object.\n */\n modifiers?: GraphModifier\n /**\n * A {@link Monorepo} object, for managing workspaces\n */\n monorepo?: Monorepo\n /**\n * A {@link PackageJson} object, for sharing manifest caches\n */\n packageJson: PackageJson\n /**\n * A {@link PathScurry} object, for use in globs\n */\n scurry: PathScurry\n /**\n * If set to `false`, `actual.load` will not load any `package.json`\n * files while traversing the file system.\n *\n * The resulting {@link Graph} from loading with `loadManifests=false`\n * has no information on dependency types or the specs defined and\n * no information on missing and extraneous dependencies.\n */\n loadManifests?: boolean\n /**\n * If set to `true`, then do not shortcut the process by reading the\n * hidden lockfile at `node_modules/.vlt-lock.json`\n */\n skipHiddenLockfile?: boolean\n /**\n * Load only importers into the graph if the modifiers have changed.\n */\n skipLoadingNodesOnModifiersChange?: boolean\n // TODO: move the lockfile-related options to a separate type file\n /**\n * If set to `true`, fail if lockfile is missing or out of date.\n * Used by ci command to enforce lockfile integrity.\n */\n expectLockfile?: boolean\n /**\n * If set to `true`, fail if lockfile is missing or out of sync with package.json.\n * Prevents any lockfile modifications and is stricter than expectLockfile.\n */\n frozenLockfile?: boolean\n /**\n * If set to `true`, only update the lockfile without performing any node_modules\n * operations. Skips package extraction, filesystem operations, and hidden lockfile saves.\n */\n lockfileOnly?: boolean\n}\n\nexport type ReadEntry = {\n alias: string\n name: string\n realpath: Path\n}\n\n/**\n * The configuration object type as it is saved in the `.vlt/vlt.json`\n */\nexport type StoreConfigObject = {\n modifiers: Record<string, string> | undefined\n}\n\n/**\n * Checks if a given object is a {@link StoreConfigObject}.\n */\nexport const isStoreConfigObject = (\n obj: unknown,\n): obj is StoreConfigObject =>\n isObject(obj) &&\n Object.prototype.hasOwnProperty.call(obj, 'modifiers') &&\n isObject(obj.modifiers)\n\n/**\n * Returns a {@link StoreConfigObject} from a given object.\n * Throws a TypeError if the object can't be converted.\n */\nexport const asStoreConfigObject = (\n obj: unknown,\n): StoreConfigObject => {\n if (!isStoreConfigObject(obj)) {\n throw new TypeError(`Expected a store config object, got ${obj}`)\n }\n return obj\n}\n\n// path-based refer to the types of dependencies that are directly linked to\n// their real location in the file system and thus will not have an entry\n// in the `node_modules/.vlt` store\nconst pathBasedType = new Set(['file', 'workspace'])\nconst isPathBasedType = (\n type: string,\n): type is 'file' | 'workspace' => pathBasedType.has(type)\n\n/**\n * Returns a {@link DepID} for a given spec and path, if the spec is\n * path-based or a registry spec, otherwise returns `undefined`.\n */\nexport const getPathBasedId = (\n spec: Spec,\n path: Path,\n): DepID | undefined =>\n isPathBasedType(spec.type) ?\n joinDepIDTuple([spec.type, path.relativePosix()])\n : findDepID(path)\n\n/**\n * Retrieve the {@link DepID} for a given package from its location.\n */\nconst findDepID = ({ parent, name }: Path): DepID | undefined =>\n parent?.name === '.vlt' ? asDepID(name)\n : parent?.isCWD === false ? findDepID(parent)\n : undefined\n\n/**\n * Retrieves the closest `node_modules` parent {@link Path} found.\n */\nconst findNodeModules = ({\n parent,\n name,\n isCWD,\n}: Path): Path | undefined =>\n parent?.name === 'node_modules' ? parent\n : parent && name !== '.vlt' && !isCWD ? findNodeModules(parent)\n : undefined\n\n/**\n * Retrieves the scoped-normalized package name from its {@link Path}.\n */\nconst findName = ({ parent, name }: Path): string =>\n parent?.name.startsWith('@') ? `${parent.name}/${name}` : name\n\n/**\n * Helper function that gets a modified {@link Spec} when finding a modifier\n * that applies to a given dependency. Otherwise returns the original spec\n * value and no queryModifier.\n */\nconst maybeApplyModifierToSpec = (\n spec: Spec,\n depName: string,\n modifierRefs?: Map<string, ModifierActiveEntry>,\n): { spec: Spec; queryModifier?: string } => {\n const activeModifier = modifierRefs?.get(depName)\n const queryModifier = activeModifier?.modifier.query\n const completeModifier =\n activeModifier &&\n activeModifier.interactiveBreadcrumb.current ===\n activeModifier.modifier.breadcrumb.last\n\n if (\n queryModifier &&\n completeModifier &&\n 'spec' in activeModifier.modifier\n ) {\n const modifiedSpec = activeModifier.modifier.spec\n modifiedSpec.overridden = true\n return { spec: modifiedSpec, queryModifier }\n }\n\n return { spec, queryModifier }\n}\n\n/**\n * Reads the current directory defined at `currDir` and looks for folder\n * names and their realpath resolution, normalizing scoped package names\n * and removing any invalid symlinks from the list of items that should\n * be parsed through in order to build the graph.\n */\nconst readDir = (\n scurry: PathScurry,\n currDir: Path,\n fromNodeName?: string,\n) => {\n const res = new Set<ReadEntry>()\n for (const entry of scurry.readdirSync(currDir)) {\n // ignore any hidden files / folders\n if (entry.name.startsWith('.')) continue\n\n // scope folder found, it will need to be read and iterated over\n // in order to find any scoped packages inside\n if (entry.name.startsWith('@')) {\n const scopedItems = readDir(scurry, entry, fromNodeName)\n for (const scopedItem of scopedItems) {\n res.add(scopedItem)\n }\n continue\n }\n\n // skip anything that isn't a symlink, it's not an edge\n if (!entry.isSymbolicLink()) continue\n\n // we'll need to learn what is the real path for this entry in order\n // to retrieve the `location` and `id` properties for the node, if a\n // realpath is not found just move on to the next element\n const realpath = entry.realpathSync()\n if (!realpath) {\n continue\n }\n\n // infer both the alias and proper package names, including scopes\n const alias = findName(entry)\n const name = findName(realpath)\n res.add({\n alias,\n name,\n realpath,\n })\n }\n return res\n}\n\n/**\n * Parses the files located at `currDir` and place packages found inside\n * as dependencies of `fromNode`, building the instantiated `graph`.\n */\nconst parseDir = (\n options: LoadOptions,\n scurry: PathScurry,\n packageJson: PackageJson,\n depsFound: Map<Node, Path>,\n graph: Graph,\n fromNode: Node,\n currDir: Path,\n) => {\n const { loadManifests, modifiers } = options\n const dependencies = getRawDependencies(fromNode)\n const seenDeps = new Set<string>()\n const readItems: Set<ReadEntry> = readDir(\n scurry,\n currDir,\n fromNode.name,\n )\n\n // Get modifier references for this node's dependencies\n const modifierRefs = modifiers?.tryDependencies(fromNode, [\n ...getDependencies(fromNode, options).values(),\n ])\n\n for (const { alias, name, realpath } of readItems) {\n let node\n\n // tracks what dependencies have been seen\n // so that we can mark missing dependencies\n seenDeps.add(alias)\n\n // places the package in the graph reading\n // its manifest only if necessary\n if (!loadManifests) {\n const depId = findDepID(realpath)\n\n if (depId) {\n let h = hydrate(depId, alias, {\n ...options,\n })\n // if the parsed registry value is using the default value, then\n // the node should inherit the registry value from its parent node\n h.inheritedRegistry = fromNode.registry\n\n // Check for active modifiers and replace spec even when not loading manifests\n const { spec: modifiedSpec, queryModifier } =\n maybeApplyModifierToSpec(h, alias, modifierRefs)\n h = modifiedSpec\n\n // graphs build with no manifest have no notion of\n // dependency types and or spec definitions since those\n // would have to be parsed from a manifest\n node = graph.placePackage(\n fromNode,\n 'prod', // defaults to prod deps\n h, // uses spec from hydrated id\n {\n name,\n },\n depId,\n queryModifier,\n )\n\n // Update active entry after placing package\n const activeModifier = modifierRefs?.get(alias)\n if (activeModifier && node) {\n modifiers?.updateActiveEntry(node, activeModifier)\n }\n }\n }\n\n // retrieve references to the current folder name found in `fromNode`\n // manifest listed dependencies, removing it from the map will leave\n // a list of missing dependencies at the end of the iteration\n const deps = dependencies.get(alias)\n\n // in case this graph is skipping manifests, this next block might\n // still need to execute, thus actually loading a manifest file, for\n // edge-cases such as loading a linked node that is not going to have\n // DepID info available in its realpath or extraneous nodes\n if (!node) {\n const mani = packageJson.read(realpath.fullpath())\n // declares fallback default values for both depType and bareSpec\n // in order to support loadManifests=false fallback for link nodes\n const type = deps?.type || 'dependencies'\n const bareSpec = deps?.bareSpec || '*'\n\n const depType = shorten(type, alias, fromNode.manifest)\n let spec = Spec.parse(alias, bareSpec, {\n ...options,\n })\n // if the parsed registry value is using the default value, then\n // the node should inherit the registry value from its parent node\n spec.inheritedRegistry = fromNode.registry\n\n // Check for active modifiers and replace spec if a modifier is complete\n const { spec: modifiedSpec, queryModifier } =\n maybeApplyModifierToSpec(spec, alias, modifierRefs)\n spec = modifiedSpec\n\n const maybeId = getPathBasedId(spec, realpath)\n node = graph.placePackage(\n fromNode,\n depType,\n spec,\n mani,\n maybeId,\n queryModifier,\n )\n\n // Update active entry after placing package\n const activeModifier = modifierRefs?.get(alias)\n if (activeModifier && node) {\n modifiers?.updateActiveEntry(node, activeModifier)\n }\n }\n\n if (node) {\n // If a found dependency is not declared in any of the original\n // node dependencies, then add an edge to the graph pointing to it\n // and mark it as extraneous.\n //\n // This only makes sense if full manifests are being loaded\n // so that we have reference to dependencies info.\n if (loadManifests && !deps) {\n const [edge] = node.edgesIn\n if (edge) {\n graph.extraneousDependencies.add(edge)\n }\n }\n\n // for a succesfully created node, add its location\n // property and queue up to read its dependencies\n node.location = `./${realpath.relativePosix()}`\n const node_modules = findNodeModules(realpath)\n\n // queue items up to continue parsing dirs in case a node was succesfully\n // placed in the graph and its node_modules folder was correctly found\n if (node_modules) {\n depsFound.set(node, node_modules)\n }\n }\n }\n\n // any remaining dependencies that have not been found\n // when reading the directory should be marked as missing\n for (const { name, type, bareSpec } of dependencies.values()) {\n if (!seenDeps.has(name)) {\n const depType = shorten(type, name, fromNode.manifest)\n let spec = Spec.parse(name, bareSpec, {\n ...options,\n })\n // if the parsed registry value is using the default value, then\n // the node should inherit the registry value from its parent node\n spec.inheritedRegistry = fromNode.registry\n\n // Check for active modifiers and replace spec for missing dependencies\n const { spec: modifiedSpec, queryModifier } =\n maybeApplyModifierToSpec(spec, name, modifierRefs)\n spec = modifiedSpec\n\n graph.placePackage(\n fromNode,\n depType,\n spec,\n undefined,\n undefined,\n queryModifier,\n )\n }\n }\n}\n\n/**\n * Read the file system looking for `node_modules` folders and\n * returns a new {@link Graph} that represents the relationship\n * between the dependencies found.\n */\nexport const load = (options: LoadOptions): Graph => {\n const done = graphStep('actual')\n const {\n modifiers,\n monorepo,\n projectRoot,\n packageJson,\n scurry,\n skipHiddenLockfile = false,\n skipLoadingNodesOnModifiersChange = false,\n } = options\n const mainManifest =\n options.mainManifest ?? packageJson.read(projectRoot)\n\n if (!skipHiddenLockfile) {\n try {\n // if we reach here, the hidden lockfile is valid\n const graph = loadHidden({\n ...options,\n projectRoot,\n mainManifest,\n packageJson,\n monorepo,\n scurry,\n })\n done()\n return graph\n } catch {\n // if validation fails or any other error occurs,\n // fall back to filesystem traversal\n }\n }\n\n const graph = new Graph({ ...options, mainManifest })\n\n // retrieve the configuration object from the store\n let storeConfig: StoreConfigObject = { modifiers: undefined }\n try {\n storeConfig = asStoreConfigObject(\n JSON.parse(\n readFileSync(\n scurry.resolve('node_modules/.vlt/vlt.json'),\n 'utf8',\n ),\n ),\n )\n } catch {}\n const storeModifiers = JSON.stringify(storeConfig.modifiers ?? {})\n const optionsModifiers = JSON.stringify(modifiers?.config)\n const modifiersChanged = storeModifiers !== optionsModifiers\n const shouldLoadDependencies = !(\n skipLoadingNodesOnModifiersChange && modifiersChanged\n )\n\n // will only skip loading dependencies if the\n // skipLoadingNodesOnModifiersChange option is set to true\n // and the current modifiers have not changed when compared\n // to the modifiers stored in the `node_modules/.vlt/vlt.json` store config\n if (shouldLoadDependencies) {\n const depsFound = new Map<Node, Path>()\n\n // starts the list of initial folders to parse using the importer nodes\n for (const importer of graph.importers) {\n modifiers?.tryImporter(importer)\n depsFound.set(\n importer,\n scurry.cwd.resolve(`${importer.location}/node_modules`),\n )\n }\n\n // breadth-first traversal of the file system tree reading deps found\n // starting from the node_modules folder of every importer in order to\n // find the actual installed dependencies at each location\n for (const [node, path] of depsFound.entries()) {\n parseDir(\n options,\n scurry,\n packageJson,\n depsFound,\n graph,\n node,\n path,\n )\n }\n\n // Clean up any pending modifier entries that were never completed\n modifiers?.rollbackActiveEntries()\n }\n\n done()\n\n return graph\n}\n"]}