@vltpkg/graph 1.0.0-rc.3 → 1.0.0-rc.30

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 (227) hide show
  1. package/README.md +101 -22
  2. package/dist/{esm/actual → actual}/load.d.ts +8 -1
  3. package/dist/{esm/actual → actual}/load.js +57 -22
  4. package/dist/{esm/browser.d.ts → browser.d.ts} +0 -1
  5. package/dist/{esm/browser.js → browser.js} +0 -1
  6. package/dist/{esm/build.d.ts → build.d.ts} +0 -1
  7. package/dist/{esm/build.js → build.js} +0 -1
  8. package/dist/{esm/dependencies.d.ts → dependencies.d.ts} +0 -1
  9. package/dist/{esm/dependencies.js → dependencies.js} +0 -1
  10. package/dist/{esm/diff.d.ts → diff.d.ts} +4 -1
  11. package/dist/{esm/diff.js → diff.js} +5 -2
  12. package/dist/{esm/edge.d.ts → edge.d.ts} +1 -1
  13. package/dist/{esm/edge.js → edge.js} +4 -1
  14. package/dist/fixup-added-names.d.ts +18 -0
  15. package/dist/fixup-added-names.js +46 -0
  16. package/dist/{esm/graph.d.ts → graph.d.ts} +25 -5
  17. package/dist/{esm/graph.js → graph.js} +92 -43
  18. package/dist/ideal/append-nodes.d.ts +31 -0
  19. package/dist/ideal/append-nodes.js +560 -0
  20. package/dist/{esm/ideal → ideal}/build-ideal-from-starting-graph.d.ts +4 -5
  21. package/dist/ideal/build-ideal-from-starting-graph.js +69 -0
  22. package/dist/{esm/ideal → ideal}/build.d.ts +0 -1
  23. package/dist/ideal/build.js +84 -0
  24. package/dist/{esm/ideal → ideal}/get-importer-specs.d.ts +9 -3
  25. package/dist/{esm/ideal → ideal}/get-importer-specs.js +80 -6
  26. package/dist/ideal/peers.d.ts +160 -0
  27. package/dist/ideal/peers.js +696 -0
  28. package/dist/ideal/refresh-ideal-graph.d.ts +43 -0
  29. package/dist/ideal/refresh-ideal-graph.js +62 -0
  30. package/dist/{esm/ideal → ideal}/remove-satisfied-specs.d.ts +0 -1
  31. package/dist/{esm/ideal → ideal}/remove-satisfied-specs.js +8 -1
  32. package/dist/ideal/sorting.d.ts +45 -0
  33. package/dist/ideal/sorting.js +70 -0
  34. package/dist/ideal/types.d.ts +107 -0
  35. package/dist/ideal/types.js +1 -0
  36. package/dist/{esm/index.d.ts → index.d.ts} +1 -1
  37. package/dist/{esm/index.js → index.js} +1 -1
  38. package/dist/{esm/install.d.ts → install.d.ts} +3 -3
  39. package/dist/{esm/install.js → install.js} +49 -9
  40. package/dist/{esm/lockfile → lockfile}/load-edges.d.ts +0 -1
  41. package/dist/{esm/lockfile → lockfile}/load-edges.js +7 -4
  42. package/dist/{esm/lockfile → lockfile}/load-nodes.d.ts +0 -1
  43. package/dist/{esm/lockfile → lockfile}/load-nodes.js +10 -4
  44. package/dist/{esm/lockfile → lockfile}/load.d.ts +0 -5
  45. package/dist/{esm/lockfile → lockfile}/load.js +31 -33
  46. package/dist/{esm/lockfile → lockfile}/save.d.ts +1 -2
  47. package/dist/{esm/lockfile → lockfile}/save.js +8 -7
  48. package/dist/{esm/lockfile → lockfile}/types.d.ts +7 -1
  49. package/dist/{esm/lockfile → lockfile}/types.js +6 -1
  50. package/dist/{esm/modifiers.d.ts → modifiers.d.ts} +0 -1
  51. package/dist/{esm/modifiers.js → modifiers.js} +0 -1
  52. package/dist/{esm/node.d.ts → node.d.ts} +16 -1
  53. package/dist/{esm/node.js → node.js} +21 -1
  54. package/dist/{esm/non-empty-list.d.ts → non-empty-list.d.ts} +0 -1
  55. package/dist/{esm/non-empty-list.js → non-empty-list.js} +0 -1
  56. package/dist/{esm/reify → reify}/add-edge.d.ts +0 -1
  57. package/dist/{esm/reify → reify}/add-edge.js +10 -4
  58. package/dist/{esm/reify → reify}/add-edges.d.ts +1 -2
  59. package/dist/{esm/reify → reify}/add-edges.js +2 -2
  60. package/dist/{esm/reify → reify}/add-nodes.d.ts +0 -1
  61. package/dist/{esm/reify → reify}/add-nodes.js +0 -1
  62. package/dist/{esm/reify → reify}/bin-chmod.d.ts +0 -1
  63. package/dist/{esm/reify → reify}/bin-chmod.js +0 -1
  64. package/dist/{esm/reify → reify}/build.d.ts +0 -1
  65. package/dist/{esm/reify → reify}/build.js +12 -4
  66. package/dist/{esm/reify → reify}/calculate-save-value.d.ts +0 -1
  67. package/dist/{esm/reify → reify}/calculate-save-value.js +6 -1
  68. package/dist/{esm/reify → reify}/check-needed-build.d.ts +10 -1
  69. package/dist/reify/check-needed-build.js +71 -0
  70. package/dist/{esm/reify → reify}/delete-edge.d.ts +0 -1
  71. package/dist/{esm/reify → reify}/delete-edge.js +0 -1
  72. package/dist/{esm/reify → reify}/delete-edges.d.ts +0 -1
  73. package/dist/{esm/reify → reify}/delete-edges.js +0 -1
  74. package/dist/{esm/reify → reify}/delete-nodes.d.ts +0 -1
  75. package/dist/{esm/reify → reify}/delete-nodes.js +0 -1
  76. package/dist/{esm/reify → reify}/extract-node.d.ts +0 -1
  77. package/dist/{esm/reify → reify}/extract-node.js +10 -3
  78. package/dist/{esm/reify → reify}/index.d.ts +1 -1
  79. package/dist/{esm/reify → reify}/index.js +4 -4
  80. package/dist/{esm/reify → reify}/internal-hoist.d.ts +0 -1
  81. package/dist/{esm/reify → reify}/internal-hoist.js +0 -1
  82. package/dist/{esm/reify → reify}/optional-fail.d.ts +0 -1
  83. package/dist/{esm/reify → reify}/optional-fail.js +0 -1
  84. package/dist/{esm/reify → reify}/rollback.d.ts +0 -1
  85. package/dist/{esm/reify → reify}/rollback.js +0 -1
  86. package/dist/{esm/reify → reify}/update-importers-package-json.d.ts +1 -2
  87. package/dist/{esm/reify → reify}/update-importers-package-json.js +19 -17
  88. package/dist/{esm/remove-optional-subgraph.d.ts → remove-optional-subgraph.d.ts} +0 -1
  89. package/dist/{esm/remove-optional-subgraph.js → remove-optional-subgraph.js} +0 -1
  90. package/dist/{esm/resolve-save-type.d.ts → resolve-save-type.d.ts} +0 -1
  91. package/dist/{esm/resolve-save-type.js → resolve-save-type.js} +0 -1
  92. package/dist/{esm/stringify-node.d.ts → stringify-node.d.ts} +0 -1
  93. package/dist/{esm/stringify-node.js → stringify-node.js} +10 -2
  94. package/dist/{esm/transfer-data → transfer-data}/load.d.ts +0 -1
  95. package/dist/{esm/transfer-data → transfer-data}/load.js +5 -3
  96. package/dist/{esm/uninstall.d.ts → uninstall.d.ts} +0 -1
  97. package/dist/{esm/uninstall.js → uninstall.js} +27 -7
  98. package/dist/{esm/update.d.ts → update.d.ts} +0 -1
  99. package/dist/{esm/update.js → update.js} +11 -1
  100. package/dist/{esm/virtual-root.d.ts → virtual-root.d.ts} +0 -1
  101. package/dist/{esm/virtual-root.js → virtual-root.js} +0 -1
  102. package/dist/{esm/visualization → visualization}/human-readable-output.d.ts +0 -1
  103. package/dist/{esm/visualization → visualization}/human-readable-output.js +7 -3
  104. package/dist/{esm/visualization → visualization}/json-output.d.ts +2 -2
  105. package/dist/{esm/visualization → visualization}/json-output.js +2 -3
  106. package/dist/{esm/visualization → visualization}/mermaid-output.d.ts +2 -2
  107. package/dist/visualization/mermaid-output.js +170 -0
  108. package/dist/{esm/visualization → visualization}/object-like-output.d.ts +0 -1
  109. package/dist/{esm/visualization → visualization}/object-like-output.js +0 -1
  110. package/package.json +51 -63
  111. package/dist/esm/actual/load.d.ts.map +0 -1
  112. package/dist/esm/actual/load.js.map +0 -1
  113. package/dist/esm/browser.d.ts.map +0 -1
  114. package/dist/esm/browser.js.map +0 -1
  115. package/dist/esm/build.d.ts.map +0 -1
  116. package/dist/esm/build.js.map +0 -1
  117. package/dist/esm/dependencies.d.ts.map +0 -1
  118. package/dist/esm/dependencies.js.map +0 -1
  119. package/dist/esm/diff.d.ts.map +0 -1
  120. package/dist/esm/diff.js.map +0 -1
  121. package/dist/esm/edge.d.ts.map +0 -1
  122. package/dist/esm/edge.js.map +0 -1
  123. package/dist/esm/graph.d.ts.map +0 -1
  124. package/dist/esm/graph.js.map +0 -1
  125. package/dist/esm/ideal/add-nodes.d.ts +0 -34
  126. package/dist/esm/ideal/add-nodes.d.ts.map +0 -1
  127. package/dist/esm/ideal/add-nodes.js +0 -39
  128. package/dist/esm/ideal/add-nodes.js.map +0 -1
  129. package/dist/esm/ideal/append-nodes.d.ts +0 -19
  130. package/dist/esm/ideal/append-nodes.d.ts.map +0 -1
  131. package/dist/esm/ideal/append-nodes.js +0 -289
  132. package/dist/esm/ideal/append-nodes.js.map +0 -1
  133. package/dist/esm/ideal/build-ideal-from-starting-graph.d.ts.map +0 -1
  134. package/dist/esm/ideal/build-ideal-from-starting-graph.js +0 -55
  135. package/dist/esm/ideal/build-ideal-from-starting-graph.js.map +0 -1
  136. package/dist/esm/ideal/build.d.ts.map +0 -1
  137. package/dist/esm/ideal/build.js +0 -48
  138. package/dist/esm/ideal/build.js.map +0 -1
  139. package/dist/esm/ideal/get-importer-specs.d.ts.map +0 -1
  140. package/dist/esm/ideal/get-importer-specs.js.map +0 -1
  141. package/dist/esm/ideal/remove-nodes.d.ts +0 -7
  142. package/dist/esm/ideal/remove-nodes.d.ts.map +0 -1
  143. package/dist/esm/ideal/remove-nodes.js +0 -19
  144. package/dist/esm/ideal/remove-nodes.js.map +0 -1
  145. package/dist/esm/ideal/remove-satisfied-specs.d.ts.map +0 -1
  146. package/dist/esm/ideal/remove-satisfied-specs.js.map +0 -1
  147. package/dist/esm/ideal/types.d.ts +0 -35
  148. package/dist/esm/ideal/types.d.ts.map +0 -1
  149. package/dist/esm/ideal/types.js +0 -2
  150. package/dist/esm/ideal/types.js.map +0 -1
  151. package/dist/esm/index.d.ts.map +0 -1
  152. package/dist/esm/index.js.map +0 -1
  153. package/dist/esm/install.d.ts.map +0 -1
  154. package/dist/esm/install.js.map +0 -1
  155. package/dist/esm/lockfile/load-edges.d.ts.map +0 -1
  156. package/dist/esm/lockfile/load-edges.js.map +0 -1
  157. package/dist/esm/lockfile/load-nodes.d.ts.map +0 -1
  158. package/dist/esm/lockfile/load-nodes.js.map +0 -1
  159. package/dist/esm/lockfile/load.d.ts.map +0 -1
  160. package/dist/esm/lockfile/load.js.map +0 -1
  161. package/dist/esm/lockfile/save.d.ts.map +0 -1
  162. package/dist/esm/lockfile/save.js.map +0 -1
  163. package/dist/esm/lockfile/types.d.ts.map +0 -1
  164. package/dist/esm/lockfile/types.js.map +0 -1
  165. package/dist/esm/modifiers.d.ts.map +0 -1
  166. package/dist/esm/modifiers.js.map +0 -1
  167. package/dist/esm/node.d.ts.map +0 -1
  168. package/dist/esm/node.js.map +0 -1
  169. package/dist/esm/non-empty-list.d.ts.map +0 -1
  170. package/dist/esm/non-empty-list.js.map +0 -1
  171. package/dist/esm/package.json +0 -3
  172. package/dist/esm/reify/add-edge.d.ts.map +0 -1
  173. package/dist/esm/reify/add-edge.js.map +0 -1
  174. package/dist/esm/reify/add-edges.d.ts.map +0 -1
  175. package/dist/esm/reify/add-edges.js.map +0 -1
  176. package/dist/esm/reify/add-nodes.d.ts.map +0 -1
  177. package/dist/esm/reify/add-nodes.js.map +0 -1
  178. package/dist/esm/reify/bin-chmod.d.ts.map +0 -1
  179. package/dist/esm/reify/bin-chmod.js.map +0 -1
  180. package/dist/esm/reify/build.d.ts.map +0 -1
  181. package/dist/esm/reify/build.js.map +0 -1
  182. package/dist/esm/reify/calculate-save-value.d.ts.map +0 -1
  183. package/dist/esm/reify/calculate-save-value.js.map +0 -1
  184. package/dist/esm/reify/check-needed-build.d.ts.map +0 -1
  185. package/dist/esm/reify/check-needed-build.js +0 -50
  186. package/dist/esm/reify/check-needed-build.js.map +0 -1
  187. package/dist/esm/reify/delete-edge.d.ts.map +0 -1
  188. package/dist/esm/reify/delete-edge.js.map +0 -1
  189. package/dist/esm/reify/delete-edges.d.ts.map +0 -1
  190. package/dist/esm/reify/delete-edges.js.map +0 -1
  191. package/dist/esm/reify/delete-nodes.d.ts.map +0 -1
  192. package/dist/esm/reify/delete-nodes.js.map +0 -1
  193. package/dist/esm/reify/extract-node.d.ts.map +0 -1
  194. package/dist/esm/reify/extract-node.js.map +0 -1
  195. package/dist/esm/reify/index.d.ts.map +0 -1
  196. package/dist/esm/reify/index.js.map +0 -1
  197. package/dist/esm/reify/internal-hoist.d.ts.map +0 -1
  198. package/dist/esm/reify/internal-hoist.js.map +0 -1
  199. package/dist/esm/reify/optional-fail.d.ts.map +0 -1
  200. package/dist/esm/reify/optional-fail.js.map +0 -1
  201. package/dist/esm/reify/rollback.d.ts.map +0 -1
  202. package/dist/esm/reify/rollback.js.map +0 -1
  203. package/dist/esm/reify/update-importers-package-json.d.ts.map +0 -1
  204. package/dist/esm/reify/update-importers-package-json.js.map +0 -1
  205. package/dist/esm/remove-optional-subgraph.d.ts.map +0 -1
  206. package/dist/esm/remove-optional-subgraph.js.map +0 -1
  207. package/dist/esm/resolve-save-type.d.ts.map +0 -1
  208. package/dist/esm/resolve-save-type.js.map +0 -1
  209. package/dist/esm/stringify-node.d.ts.map +0 -1
  210. package/dist/esm/stringify-node.js.map +0 -1
  211. package/dist/esm/transfer-data/load.d.ts.map +0 -1
  212. package/dist/esm/transfer-data/load.js.map +0 -1
  213. package/dist/esm/uninstall.d.ts.map +0 -1
  214. package/dist/esm/uninstall.js.map +0 -1
  215. package/dist/esm/update.d.ts.map +0 -1
  216. package/dist/esm/update.js.map +0 -1
  217. package/dist/esm/virtual-root.d.ts.map +0 -1
  218. package/dist/esm/virtual-root.js.map +0 -1
  219. package/dist/esm/visualization/human-readable-output.d.ts.map +0 -1
  220. package/dist/esm/visualization/human-readable-output.js.map +0 -1
  221. package/dist/esm/visualization/json-output.d.ts.map +0 -1
  222. package/dist/esm/visualization/json-output.js.map +0 -1
  223. package/dist/esm/visualization/mermaid-output.d.ts.map +0 -1
  224. package/dist/esm/visualization/mermaid-output.js +0 -123
  225. package/dist/esm/visualization/mermaid-output.js.map +0 -1
  226. package/dist/esm/visualization/object-like-output.d.ts.map +0 -1
  227. package/dist/esm/visualization/object-like-output.js.map +0 -1
@@ -0,0 +1,43 @@
1
+ import type { PathScurry } from 'path-scurry';
2
+ import type { PackageInfoClient } from '@vltpkg/package-info';
3
+ import type { SpecOptions } from '@vltpkg/spec';
4
+ import type { RollbackRemove } from '@vltpkg/rollback-remove';
5
+ import type { BuildIdealAddOptions, BuildIdealFromGraphOptions, BuildIdealRemoveOptions, TransientAddMap, TransientRemoveMap } from './types.ts';
6
+ import type { GraphModifier } from '../modifiers.ts';
7
+ import type { Graph } from '../graph.ts';
8
+ export type RefreshIdealGraphOptions = BuildIdealAddOptions & BuildIdealRemoveOptions & BuildIdealFromGraphOptions & SpecOptions & {
9
+ /**
10
+ * The graph modifiers helper object.
11
+ */
12
+ modifiers?: GraphModifier;
13
+ /**
14
+ * A {@link PathScurry} instance based on the `projectRoot` path
15
+ */
16
+ scurry: PathScurry;
17
+ /**
18
+ * A {@link PackageInfoClient} instance to read manifest info from.
19
+ */
20
+ packageInfo: PackageInfoClient;
21
+ /**
22
+ * The actual graph to compare against for early extraction
23
+ */
24
+ actual?: Graph;
25
+ /**
26
+ * A {@link RollbackRemove} instance to handle extraction rollbacks
27
+ */
28
+ remover: RollbackRemove;
29
+ /**
30
+ * Dependencies to be added to non-importer nodes when they are placed.
31
+ * Used for nested folder dependencies that are not importers.
32
+ */
33
+ transientAdd?: TransientAddMap;
34
+ /**
35
+ * Dependencies to be removed from non-importer nodes when they are placed.
36
+ * Used for nested folder dependencies that are not importers.
37
+ */
38
+ transientRemove?: TransientRemoveMap;
39
+ };
40
+ /**
41
+ * Rebuilds the provided ideal graph.
42
+ */
43
+ export declare const refreshIdealGraph: ({ add, graph, modifiers, packageInfo, scurry, actual, remove, remover, transientAdd, transientRemove, ...specOptions }: RefreshIdealGraphOptions) => Promise<void>;
@@ -0,0 +1,62 @@
1
+ import { appendNodes } from "./append-nodes.js";
2
+ import { compareByHasPeerDeps, getNodeOrderedDependencies, } from "./sorting.js";
3
+ /**
4
+ * Returns an ordered list of importer nodes.
5
+ */
6
+ const getOrderedImporters = (graph) => {
7
+ const orderedImporters = [...graph.importers].sort((a, b) => {
8
+ // mainImporter always comes first
9
+ /* c8 ignore next */
10
+ if (a === graph.mainImporter)
11
+ return -1;
12
+ if (b === graph.mainImporter)
13
+ return 1;
14
+ return compareByHasPeerDeps({ manifest: a.manifest }, { manifest: b.manifest });
15
+ });
16
+ return orderedImporters;
17
+ };
18
+ /**
19
+ * Rebuilds the provided ideal graph.
20
+ */
21
+ export const refreshIdealGraph = async ({ add, graph, modifiers, packageInfo, scurry, actual, remove, remover, transientAdd, transientRemove, ...specOptions }) => {
22
+ const seen = new Set();
23
+ const extractPromises = [];
24
+ const seenExtracted = new Set();
25
+ // gets an ordered list of importers to ensure deterministic processing
26
+ const orderedImporters = getOrderedImporters(graph);
27
+ const depsPerImporter = new Map();
28
+ for (const importer of orderedImporters) {
29
+ // gets an ordered list of dependencies for this importer
30
+ // while also taking into account additions and removals
31
+ const deps = getNodeOrderedDependencies(importer, { add, remove });
32
+ depsPerImporter.set(importer, deps);
33
+ }
34
+ // removes all edges to start recalculating the graph
35
+ if (add.modifiedDependencies || remove.modifiedDependencies) {
36
+ graph.resetEdges();
37
+ }
38
+ // iterates on the list of dependencies per importer updating
39
+ // the graph using metadata fetch from the registry manifest files
40
+ for (const importer of orderedImporters) {
41
+ modifiers?.tryImporter(importer);
42
+ // gets a ref to the map of dependencies being added to this importer
43
+ const addedDeps = add.get(importer.id);
44
+ const deps = depsPerImporter.get(importer);
45
+ /* c8 ignore next */
46
+ if (!deps)
47
+ continue;
48
+ // gets a ref to the list of modifier functions for this set of deps
49
+ const modifierRefs = modifiers?.tryDependencies(importer, deps);
50
+ // Add new nodes for packages defined in the dependencies list fetching
51
+ // metadata from the registry manifests and updating the graph
52
+ await appendNodes(packageInfo, graph, importer, deps, scurry, specOptions, seen, addedDeps, modifiers, modifierRefs, extractPromises, actual, seenExtracted, remover, transientAdd, transientRemove);
53
+ }
54
+ // set default node locations, if possible
55
+ for (const node of graph.nodes.values()) {
56
+ node.setDefaultLocation();
57
+ }
58
+ // Wait for all extraction promises to complete
59
+ if (extractPromises.length > 0) {
60
+ await Promise.all(extractPromises);
61
+ }
62
+ };
@@ -5,4 +5,3 @@ export type RemoveSatisfiedSpecsOptions = BuildIdealAddOptions & BuildIdealFromG
5
5
  * that are already satisfied by the contents of the actual `graph`.
6
6
  */
7
7
  export declare const removeSatisfiedSpecs: ({ add, graph, }: RemoveSatisfiedSpecsOptions) => void;
8
- //# sourceMappingURL=remove-satisfied-specs.d.ts.map
@@ -18,6 +18,14 @@ export const removeSatisfiedSpecs = ({ add, graph, }) => {
18
18
  // brand new edge being added
19
19
  continue;
20
20
  }
21
+ // If the spec type has changed (e.g., from "registry" to
22
+ // "catalog" or vice versa), keep it in the add list so the
23
+ // edge gets rebuilt with the updated spec, even if the
24
+ // resolved node is the same.
25
+ const edgeIsCatalog = edge.spec.type === 'catalog';
26
+ const depIsCatalog = dependency.spec.type === 'catalog';
27
+ if (edgeIsCatalog !== depIsCatalog)
28
+ continue;
21
29
  // If the current graph edge is already valid, then we remove that
22
30
  // dependency item from the list of items to be added to the graph
23
31
  if (satisfies(edge.to?.id, dependency.spec, edge.from.location, graph.projectRoot, graph.monorepo)) {
@@ -32,4 +40,3 @@ export const removeSatisfiedSpecs = ({ add, graph, }) => {
32
40
  }
33
41
  }
34
42
  };
35
- //# sourceMappingURL=remove-satisfied-specs.js.map
@@ -0,0 +1,45 @@
1
+ import type { BuildIdealAddOptions, BuildIdealRemoveOptions } from './types.ts';
2
+ import type { Spec } from '@vltpkg/spec';
3
+ import type { Manifest, NormalizedManifest } from '@vltpkg/types';
4
+ import type { Node } from '../node.ts';
5
+ import type { Dependency } from '../dependencies.ts';
6
+ type SortableByHasPeerDeps = {
7
+ /** Package manifest containing dependency information */
8
+ manifest?: Manifest | NormalizedManifest;
9
+ /** Package name */
10
+ name?: string;
11
+ /** Package specifier */
12
+ spec?: Spec;
13
+ };
14
+ type SortableByType = {
15
+ /** Dependency type (e.g., 'prod', 'dev', 'peer', 'peerOptional') */
16
+ type: string;
17
+ /** Target node with package name */
18
+ target?: {
19
+ name: string;
20
+ };
21
+ /** Package specifier */
22
+ spec?: Spec;
23
+ };
24
+ /**
25
+ * Checks if a dependency type is a peer dependency.
26
+ */
27
+ export declare const isPeerType: (type: string) => type is "peer" | "peerOptional";
28
+ /**
29
+ * Sorts a list of dependencies by whether they have peer dependencies.
30
+ */
31
+ export declare const compareByHasPeerDeps: (a: SortableByHasPeerDeps, b: SortableByHasPeerDeps) => number;
32
+ /**
33
+ * Sorts a list of dependencies by type and name.
34
+ */
35
+ export declare const compareByType: (a: SortableByType, b: SortableByType) => number;
36
+ /**
37
+ * Computes the ordered list of dependencies for an given node,
38
+ * taking into account additions and removals.
39
+ */
40
+ export declare const getNodeOrderedDependencies: (fromNode: Node, options?: BuildIdealAddOptions & BuildIdealRemoveOptions) => Dependency[];
41
+ /**
42
+ * Sorts a list of dependencies by type.
43
+ */
44
+ export declare const getOrderedDependencies: (deps: Dependency[]) => Dependency[];
45
+ export {};
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Checks if a dependency type is a peer dependency.
3
+ */
4
+ export const isPeerType = (type) => type === 'peer' || type === 'peerOptional';
5
+ /**
6
+ * Sorts a list of dependencies by whether they have peer dependencies.
7
+ */
8
+ export const compareByHasPeerDeps = (a, b) => {
9
+ const aHasPeer = (a.manifest?.peerDependencies &&
10
+ Object.keys(a.manifest.peerDependencies).length > 0) ?
11
+ 1
12
+ : 0;
13
+ const bHasPeer = (b.manifest?.peerDependencies &&
14
+ Object.keys(b.manifest.peerDependencies).length > 0) ?
15
+ 1
16
+ : 0;
17
+ if (aHasPeer !== bHasPeer)
18
+ return aHasPeer - bHasPeer;
19
+ const aName = a.manifest?.name || a.spec?.name || a.name || '';
20
+ const bName = b.manifest?.name ||
21
+ /* c8 ignore next - very hard to test */ b.spec?.name ||
22
+ b.name ||
23
+ '';
24
+ return aName.localeCompare(bName, 'en');
25
+ };
26
+ /**
27
+ * Sorts a list of dependencies by type and name.
28
+ */
29
+ export const compareByType = (a, b) => {
30
+ const aIsPeer = isPeerType(a.type) ? 1 : 0;
31
+ const bIsPeer = isPeerType(b.type) ? 1 : 0;
32
+ if (aIsPeer !== bIsPeer)
33
+ return aIsPeer - bIsPeer;
34
+ const aName = a.target?.name ?? a.spec?.name ?? '';
35
+ const bName = b.target?.name ?? b.spec?.name ?? '';
36
+ return aName.localeCompare(bName, 'en');
37
+ };
38
+ /**
39
+ * Computes the ordered list of dependencies for an given node,
40
+ * taking into account additions and removals.
41
+ */
42
+ export const getNodeOrderedDependencies = (fromNode, options) => {
43
+ // using a map here instead of an array helps us get simpler
44
+ // deduplication while iterating through all the items at hand:
45
+ // existing dependencies in the graph, dependencies to be added, etc.
46
+ const deps = new Map();
47
+ for (const [name, { spec, type }] of fromNode.edgesOut.entries()) {
48
+ deps.set(name, { spec, type });
49
+ }
50
+ // next iterate through the list of dependencies to be added
51
+ const addedDeps = options?.add.get(fromNode.id);
52
+ if (addedDeps) {
53
+ for (const [name, { spec, type }] of addedDeps.entries()) {
54
+ deps.set(name, { spec, type });
55
+ }
56
+ }
57
+ // finally iterate through the list of dependencies to be removed
58
+ const removedDeps = options?.remove.get(fromNode.id);
59
+ if (removedDeps) {
60
+ for (const name of removedDeps) {
61
+ deps.delete(name);
62
+ }
63
+ }
64
+ // now turn the map into a sorted array
65
+ return getOrderedDependencies([...deps.values()]);
66
+ };
67
+ /**
68
+ * Sorts a list of dependencies by type.
69
+ */
70
+ export const getOrderedDependencies = (deps) => [...deps].sort(compareByType);
@@ -0,0 +1,107 @@
1
+ import type { PackageInfoClient } from '@vltpkg/package-info';
2
+ import type { Spec } from '@vltpkg/spec';
3
+ import type { DependencySaveType } from '@vltpkg/types';
4
+ import type { AddImportersDependenciesMap, Dependency, RemoveImportersDependenciesMap } from '../dependencies.ts';
5
+ import type { ModifierActiveEntry } from '../modifiers.ts';
6
+ import type { Graph } from '../graph.ts';
7
+ import type { Node } from '../node.ts';
8
+ /**
9
+ * A map of dependencies to be added to non-importer nodes.
10
+ * Keys are {@link DepID} of nodes that are not importers (e.g., nested folders).
11
+ * When these nodes are resolved and placed in the graph, their dependencies
12
+ * from this map are injected into the processing queue.
13
+ */
14
+ export type TransientAddMap = Omit<AddImportersDependenciesMap, 'modifiedDependencies'>;
15
+ /**
16
+ * A map of dependency names to be removed from non-importer nodes.
17
+ * Keys are {@link DepID} of nodes that are not importers (e.g., nested folders).
18
+ * When these nodes are processed, their dependencies in this map are excluded.
19
+ */
20
+ export type TransientRemoveMap = Omit<RemoveImportersDependenciesMap, 'modifiedDependencies'>;
21
+ export type BuildIdealAddOptions = {
22
+ /**
23
+ * A {@link AddImportersDependenciesMap} in which keys are {@link DepID}
24
+ * linking to another `Map` in which keys are the dependency names and values
25
+ * are {@link Dependency}. This structure represents dependencies that need
26
+ * to be added to the importer represented by {@link DepID}.
27
+ */
28
+ add: AddImportersDependenciesMap;
29
+ };
30
+ export type BuildIdealRemoveOptions = {
31
+ /**
32
+ * A {@link RemoveImportersDependenciesMap} object representing nodes to be
33
+ * removed from the ideal graph. Each {@link DepID} key represents an
34
+ * importer node and the `Set` of dependency names to be removed from its
35
+ * dependency list.
36
+ */
37
+ remove: RemoveImportersDependenciesMap;
38
+ };
39
+ export type BuildIdealFromGraphOptions = {
40
+ /**
41
+ * An initial {@link Graph} to start building from, adding nodes to any
42
+ * missing edges and appending any new specs defined in `addSpecs`.
43
+ */
44
+ graph: Graph;
45
+ };
46
+ export type BuildIdealPackageInfoOptions = {
47
+ /**
48
+ * A {@link PackageInfoClient} instance to read manifest info from.
49
+ */
50
+ packageInfo: PackageInfoClient;
51
+ };
52
+ /**
53
+ * Represents an ongoing append operation for a node and its dependencies.
54
+ */
55
+ export type AppendNodeEntry = {
56
+ node: Node;
57
+ deps: Dependency[];
58
+ modifierRefs?: Map<string, ModifierActiveEntry>;
59
+ depth: number;
60
+ peerContext: PeerContext;
61
+ updateContext: {
62
+ putEntries: () => PeerContextEntryInput[] | undefined;
63
+ resolvePeerDeps: () => void;
64
+ };
65
+ };
66
+ /**
67
+ * The result of processing a given placed node in the graph.
68
+ */
69
+ export type ProcessPlacementResultEntry = Omit<AppendNodeEntry, 'depth'>;
70
+ /**
71
+ * The result of processing placement for nodes to be added to the graph.
72
+ */
73
+ export type ProcessPlacementResult = ProcessPlacementResultEntry[];
74
+ /**
75
+ * Entry in a peer context representing a resolved peer dependency.
76
+ */
77
+ export type PeerContextEntry = {
78
+ /**
79
+ * True if this entry is currently being resolved and track by this
80
+ * peer context set, false in case this entry was inherit from a previous
81
+ * peer context set and should not be considered for resolution.
82
+ */
83
+ active: boolean;
84
+ /** List of full Spec objects that are part of this peer context entry */
85
+ specs: Set<Spec>;
86
+ /** The target Node that satisfies all specs for this peer context entry */
87
+ target: Node | undefined;
88
+ /** The type of dependency this entry represents */
89
+ type: DependencySaveType;
90
+ /** Context dependent nodes that had dependencies resolved to this entry */
91
+ contextDependents: Set<Node>;
92
+ };
93
+ /**
94
+ * Input for adding an entry to peer contexts.
95
+ */
96
+ export type PeerContextEntryInput = {
97
+ /** Node that depends on this resolved peer context set entry */
98
+ dependent?: Node;
99
+ /** Node this peer context entry resolves to */
100
+ target?: Node;
101
+ } & Dependency;
102
+ /**
103
+ * Represents resolved peer dependencies in a given append-nodes context.
104
+ */
105
+ export type PeerContext = Map<string, PeerContextEntry> & {
106
+ index?: number;
107
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -3,6 +3,7 @@ export * from './edge.ts';
3
3
  export * from './graph.ts';
4
4
  export * from './node.ts';
5
5
  export * from './dependencies.ts';
6
+ export * from './fixup-added-names.ts';
6
7
  export * from './lockfile/types.ts';
7
8
  export * from './visualization/json-output.ts';
8
9
  export * from './visualization/human-readable-output.ts';
@@ -35,4 +36,3 @@ export declare const ideal: {
35
36
  export { reify } from './reify/index.ts';
36
37
  export type { ReifyOptions } from './reify/index.ts';
37
38
  export type { BuildResult } from './reify/build.ts';
38
- //# sourceMappingURL=index.d.ts.map
@@ -3,6 +3,7 @@ export * from "./edge.js";
3
3
  export * from "./graph.js";
4
4
  export * from "./node.js";
5
5
  export * from "./dependencies.js";
6
+ export * from "./fixup-added-names.js";
6
7
  export * from "./lockfile/types.js";
7
8
  export * from "./visualization/json-output.js";
8
9
  export * from "./visualization/human-readable-output.js";
@@ -29,4 +30,3 @@ export const lockfile = {
29
30
  import { build } from "./ideal/build.js";
30
31
  export const ideal = { build };
31
32
  export { reify } from "./reify/index.js";
32
- //# sourceMappingURL=index.js.map
@@ -2,18 +2,18 @@ import type { PackageInfoClient } from '@vltpkg/package-info';
2
2
  import type { LoadOptions } from './actual/load.ts';
3
3
  import type { AddImportersDependenciesMap } from './dependencies.ts';
4
4
  import type { DepID } from '@vltpkg/dep-id';
5
+ import type { Graph } from './index.ts';
5
6
  export type InstallOptions = LoadOptions & {
6
7
  packageInfo: PackageInfoClient;
7
8
  cleanInstall?: boolean;
8
9
  allowScripts: string;
9
10
  };
10
11
  export declare const install: (options: InstallOptions, add?: AddImportersDependenciesMap) => Promise<{
11
- graph: import("./graph.ts").Graph;
12
+ graph: Graph;
12
13
  diff: undefined;
13
14
  buildQueue?: undefined;
14
15
  } | {
15
16
  buildQueue: DepID[] | undefined;
16
- graph: import("./graph.ts").Graph;
17
+ graph: Graph;
17
18
  diff: import("./diff.ts").Diff;
18
19
  }>;
19
- //# sourceMappingURL=install.d.ts.map
@@ -7,12 +7,13 @@ import { error } from '@vltpkg/error-cause';
7
7
  import { asError } from '@vltpkg/types';
8
8
  import { getDependencies } from "./dependencies.js";
9
9
  import { RollbackRemove } from '@vltpkg/rollback-remove';
10
- import { existsSync } from 'node:fs';
10
+ import { existsSync, rmSync } from 'node:fs';
11
11
  import { resolve } from 'node:path';
12
12
  import { load as loadVirtual } from "./lockfile/load.js";
13
13
  import { getImporterSpecs } from "./ideal/get-importer-specs.js";
14
14
  import { lockfile } from "./index.js";
15
15
  import { updatePackageJson } from "./reify/update-importers-package-json.js";
16
+ import { Monorepo } from '@vltpkg/workspaces';
16
17
  export const install = async (options, add) => {
17
18
  // Validate incompatible options
18
19
  if (options.lockfileOnly && options.cleanInstall) {
@@ -41,7 +42,16 @@ export const install = async (options, add) => {
41
42
  throw err;
42
43
  }
43
44
  }
45
+ // Load an unfiltered monorepo to ensure all workspace importers are
46
+ // included in the graph. This is necessary because the options.monorepo
47
+ // may be filtered by -w/--workspace flags, which would cause nodes/edges
48
+ // from other workspaces to be lost during graph construction.
49
+ const fullMonorepo = Monorepo.maybeLoad(options.projectRoot, {
50
+ packageJson: options.packageJson,
51
+ scurry: options.scurry,
52
+ });
44
53
  if (options.frozenLockfile) {
54
+ // validates no add/remove operations are requested
45
55
  if (add?.modifiedDependencies) {
46
56
  const dependencies = [];
47
57
  for (const [, deps] of add) {
@@ -54,7 +64,7 @@ export const install = async (options, add) => {
54
64
  const lockfileGraph = loadVirtual({
55
65
  ...options,
56
66
  mainManifest,
57
- skipLoadingNodesOnModifiersChange: false,
67
+ monorepo: fullMonorepo,
58
68
  });
59
69
  const emptyAdd = Object.assign(new Map(), { modifiedDependencies: false });
60
70
  const emptyRemove = Object.assign(new Map(), {
@@ -94,7 +104,8 @@ export const install = async (options, add) => {
94
104
  const node = lockfileGraph.nodes.get(importerId);
95
105
  const location = node?.location || importerId;
96
106
  const depNames = Array.from(deps.keys());
97
- details.push(` ${location}: ${deps.size} dependencies to add (${depNames.join(', ')})`);
107
+ const depLabelAdd = deps.size === 1 ? 'dependency' : 'dependencies';
108
+ details.push(` ${location}: ${deps.size} ${depLabelAdd} to add (${depNames.join(', ')})`);
98
109
  }
99
110
  }
100
111
  for (const [importerId, deps] of importerSpecs.remove) {
@@ -102,7 +113,10 @@ export const install = async (options, add) => {
102
113
  const node = lockfileGraph.nodes.get(importerId);
103
114
  const location = node?.location || importerId;
104
115
  const depNames = Array.from(deps);
105
- details.push(` ${location}: ${deps.size} dependencies to remove (${depNames.join(', ')})`);
116
+ const depLabelRemove = deps.size === 1 ?
117
+ 'dependency'
118
+ : /* c8 ignore next */ 'dependencies';
119
+ details.push(` ${location}: ${deps.size} ${depLabelRemove} to remove (${depNames.join(', ')})`);
106
120
  }
107
121
  }
108
122
  const lockfilePath = resolve(options.projectRoot, 'vlt-lock.json');
@@ -121,13 +135,23 @@ export const install = async (options, add) => {
121
135
  }
122
136
  }
123
137
  try {
138
+ const remove = Object.assign(new Map(), {
139
+ modifiedDependencies: false,
140
+ });
124
141
  const modifiers = GraphModifier.maybeLoad(options);
125
- const act = actualLoad({
142
+ let act = actualLoad({
126
143
  ...options,
127
144
  mainManifest,
128
145
  loadManifests: true,
129
146
  modifiers: undefined, // modifiers should not be used here
147
+ monorepo: fullMonorepo,
130
148
  });
149
+ // if the actual graph has no dependencies, it's simpler to ignore it
150
+ // this allows us to check for its availability later on for properly
151
+ // handling situations like resetting edges for refreshing the ideal graph
152
+ if (act.importers.size === act.nodes.size) {
153
+ act = undefined;
154
+ }
131
155
  const graph = await idealBuild({
132
156
  ...options,
133
157
  actual: act,
@@ -135,19 +159,27 @@ export const install = async (options, add) => {
135
159
  mainManifest,
136
160
  loadManifests: true,
137
161
  modifiers,
162
+ remove,
138
163
  remover,
164
+ monorepo: fullMonorepo,
139
165
  });
140
166
  // If lockfileOnly is enabled, skip reify and only save the lockfile
141
167
  if (options.lockfileOnly) {
142
- // Save only the main lockfile, skip all filesystem operations
143
- lockfile.save({ graph, modifiers });
168
+ // Save only the main lockfile, skip all filesystem operations.
169
+ // Spread `options` so that spec-level config (registry,
170
+ // scoped-registries, git-hosts, catalogs, etc.) round-trips
171
+ // through the lockfile - otherwise subsequent installs lose
172
+ // the configured registry and rewrite node/edge DepIDs back
173
+ // to the default npm registry. (See vltpkg/vltpkg#1580.)
174
+ lockfile.save({ ...options, graph, modifiers });
144
175
  const saveImportersPackageJson =
145
176
  /* c8 ignore next */
146
- add?.modifiedDependencies ?
177
+ add?.modifiedDependencies || remove.modifiedDependencies ?
147
178
  updatePackageJson({
148
179
  ...options,
149
180
  add,
150
181
  graph,
182
+ remove,
151
183
  })
152
184
  : undefined;
153
185
  saveImportersPackageJson?.();
@@ -160,6 +192,7 @@ export const install = async (options, add) => {
160
192
  graph,
161
193
  loadManifests: true,
162
194
  modifiers,
195
+ remove,
163
196
  remover,
164
197
  });
165
198
  return { buildQueue, graph, diff };
@@ -167,7 +200,14 @@ export const install = async (options, add) => {
167
200
  catch (err) {
168
201
  /* c8 ignore next */
169
202
  await remover.rollback().catch(() => { });
203
+ // Remove hidden lockfile on failure
204
+ try {
205
+ const hiddenLockfile = resolve(options.projectRoot, 'node_modules/.vlt-lock.json');
206
+ if (existsSync(hiddenLockfile)) {
207
+ rmSync(hiddenLockfile, { force: true });
208
+ }
209
+ }
210
+ catch { }
170
211
  throw err;
171
212
  }
172
213
  };
173
- //# sourceMappingURL=install.js.map
@@ -9,4 +9,3 @@ export type ProcessingEdge = {
9
9
  spec: Spec;
10
10
  };
11
11
  export declare const loadEdges: (graph: GraphLike, edges: LockfileData["edges"], options: SpecOptions) => void;
12
- //# sourceMappingURL=load-edges.d.ts.map
@@ -78,10 +78,14 @@ export const loadEdges = (graph, edges, options) => {
78
78
  toNode = graph.nodes.get(asDepID(toId));
79
79
  }
80
80
  }
81
- // Parse spec once we know the nodes are valid
81
+ // Use the merged options directly they already carry the
82
+ // correct registry from the lockfile's `options` + caller config.
83
+ // `fromNode.registry` is not populated yet at this point (the
84
+ // post-load hydration loop in load.ts sets it *after* edges are
85
+ // loaded), so overriding here would always inject `undefined`
86
+ // and silently revert to the default npm registry.
87
+ // See vltpkg/vltpkg#1580.
82
88
  const spec = Spec.parse(specName, valRest.substring(0, vrSplit), options);
83
- // sets a registry for this spec to inherit from
84
- spec.inheritedRegistry = fromNode.registry;
85
89
  if (useOptimizations) {
86
90
  edgeProcessingQueue.push({
87
91
  fromNode,
@@ -102,4 +106,3 @@ export const loadEdges = (graph, edges, options) => {
102
106
  }
103
107
  }
104
108
  };
105
- //# sourceMappingURL=load-edges.js.map
@@ -2,4 +2,3 @@ import type { LockfileData } from './types.ts';
2
2
  import type { GraphLike } from '@vltpkg/types';
3
3
  import type { SpecOptions } from '@vltpkg/spec/browser';
4
4
  export declare const loadNodes: (graph: GraphLike, nodes: LockfileData["nodes"], options: SpecOptions, actual?: GraphLike, throwOnMissingManifest?: boolean) => void;
5
- //# sourceMappingURL=load-nodes.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import { error } from '@vltpkg/error-cause';
2
- import { splitDepID } from '@vltpkg/dep-id/browser';
2
+ import { splitDepID, splitExtra } from '@vltpkg/dep-id/browser';
3
3
  import { getBooleanFlagsFromNum, getBuildStateFromNum, } from "./types.js";
4
4
  export const loadNodes = (graph, nodes, options, actual, throwOnMissingManifest) => {
5
5
  const entries = Object.entries(nodes);
@@ -55,14 +55,21 @@ export const loadNodes = (graph, nodes, options, actual, throwOnMissingManifest)
55
55
  graph.addNode(id, mani)
56
56
  : graph.addNode(id, undefined, undefined, name ?? undefined, version);
57
57
  if (extra) {
58
- node.modifier = extra;
58
+ const { modifier, peerSetHash } = splitExtra(extra);
59
+ if (modifier) {
60
+ node.modifier = modifier;
61
+ }
62
+ if (peerSetHash) {
63
+ node.peerSetHash = peerSetHash;
64
+ }
59
65
  }
60
66
  const { dev, optional } = getBooleanFlagsFromNum(flags);
61
67
  node.options = options;
62
68
  node.dev = dev;
63
69
  node.optional = optional;
64
70
  node.integrity = integrity ?? referenceNode?.integrity;
65
- node.resolved = resolved ?? referenceNode?.resolved;
71
+ node.resolved =
72
+ type === 'remote' ? filepath : ((resolved ?? referenceNode?.resolved));
66
73
  node.projectRoot = graph.projectRoot;
67
74
  if (!node.resolved)
68
75
  node.setResolved();
@@ -92,4 +99,3 @@ export const loadNodes = (graph, nodes, options, actual, throwOnMissingManifest)
92
99
  }
93
100
  }
94
101
  };
95
- //# sourceMappingURL=load-nodes.js.map
@@ -35,10 +35,6 @@ export type LoadOptions = SpecOptions & {
35
35
  * A {@link PathScurry} object, for use in globs
36
36
  */
37
37
  scurry?: PathScurry;
38
- /**
39
- * Load only importers into the graph if the modifiers have changed.
40
- */
41
- skipLoadingNodesOnModifiersChange?: boolean;
42
38
  /**
43
39
  * Whether to throw an error if a manifest is missing when loading nodes.
44
40
  */
@@ -47,4 +43,3 @@ export type LoadOptions = SpecOptions & {
47
43
  export declare const load: (options: LoadOptions) => Graph;
48
44
  export declare const loadHidden: (options: LoadOptions) => Graph;
49
45
  export declare const loadObject: (options: LoadOptions, lockfileData: Omit<LockfileData, "options" | "lockfileVersion"> & Partial<Pick<LockfileData, "options" | "lockfileVersion">>) => Graph;
50
- //# sourceMappingURL=load.d.ts.map