@vltpkg/graph 1.0.9 → 1.1.0

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.
@@ -344,8 +344,14 @@ export const load = (options) => {
344
344
  }
345
345
  // Clean up any pending modifier entries that were never completed
346
346
  modifiers?.rollbackActiveEntries();
347
- // caches the load result to the hidden lockfile when enabled
348
- if (scurry.cwd.resolve('node_modules').lstatSync()?.isDirectory()) {
347
+ // caches the load result to the hidden lockfile, but only when the
348
+ // store exists, i.e. this node_modules was built by vlt. a walk over
349
+ // a node_modules installed by another client finds nothing, and
350
+ // must not leave a file behind that makes it look like a vlt install.
351
+ if (scurry.cwd
352
+ .resolve('node_modules/.vlt')
353
+ .lstatSync()
354
+ ?.isDirectory()) {
349
355
  saveHidden({
350
356
  ...options,
351
357
  graph,
package/dist/build.d.ts CHANGED
@@ -23,6 +23,6 @@ export interface BuildOptions extends LoadOptions {
23
23
  * 3. Constructs a Diff object representing what needs to be built
24
24
  * 4. Filters nodes based on buildState === 'needed'
25
25
  * 5. Calls the reify build process with the constructed diff
26
- * 6. Persists build results to lockfile
26
+ * 6. Persists build results to the hidden lockfile, when the vlt store exists
27
27
  */
28
28
  export declare const build: (options: BuildOptions) => Promise<BuildResult>;
package/dist/build.js CHANGED
@@ -40,7 +40,7 @@ const filterNodesByQuery = async (targetQuery, graph) => {
40
40
  * 3. Constructs a Diff object representing what needs to be built
41
41
  * 4. Filters nodes based on buildState === 'needed'
42
42
  * 5. Calls the reify build process with the constructed diff
43
- * 6. Persists build results to lockfile
43
+ * 6. Persists build results to the hidden lockfile, when the vlt store exists
44
44
  */
45
45
  export const build = async (options) => {
46
46
  const { projectRoot, packageJson, monorepo = Monorepo.maybeLoad(projectRoot), scurry, mainManifest = packageJson.read(projectRoot), target, ...loadOptions } = options;
@@ -69,10 +69,19 @@ export const build = async (options) => {
69
69
  // this will only build the nodes that need to be built
70
70
  // as part of `diff.nodes.add`
71
71
  const buildResult = await reifyBuild(diff, packageJson, scurry, targetFilteredNodes);
72
- // Save hidden lockfile with updated buildState
73
- saveHidden({
74
- ...options,
75
- graph: actualGraph,
76
- });
72
+ // Save hidden lockfile with updated buildState, but only when the
73
+ // store exists, i.e. this node_modules was built by vlt. Loading a
74
+ // node_modules installed by another client finds nothing to build,
75
+ // and must not leave a file behind that makes it look like a vlt
76
+ // install. A dependency-less vlt install has no store either, but it
77
+ // also has no nodes, so there is no build state to persist.
78
+ if (scurry
79
+ .lstatSync(scurry.resolve(projectRoot, 'node_modules/.vlt'))
80
+ ?.isDirectory()) {
81
+ saveHidden({
82
+ ...options,
83
+ graph: actualGraph,
84
+ });
85
+ }
77
86
  return buildResult;
78
87
  };
@@ -7,6 +7,7 @@ import { graphRun } from '@vltpkg/graph-run';
7
7
  import { nonEmptyList } from "../non-empty-list.js";
8
8
  import { optionalFail } from "./optional-fail.js";
9
9
  import { binChmod } from "./bin-chmod.js";
10
+ import { scriptsManifest } from "./scripts-manifest.js";
10
11
  export const build = async (diff, packageJson, scurry, allowScriptsNodes) => {
11
12
  const graph = diff.to;
12
13
  const nodes = nonEmptyList([...graph.importers]);
@@ -68,8 +69,9 @@ const visit = async (packageJson, scurry, node, signal, _path) => {
68
69
  // currently nullish, that could happen in a scenario where the ideal
69
70
  // graph is from a lockfile and there's no actual graph available
70
71
  // to hydrate the manifest data from.
71
- node.manifest ??= packageJson.read(node.resolvedLocation(scurry));
72
- const { manifest } = node;
72
+ const dir = node.resolvedLocation(scurry);
73
+ node.manifest ??= packageJson.read(dir);
74
+ const manifest = scriptsManifest(node.manifest, dir, packageJson);
73
75
  const { scripts = {} } = manifest;
74
76
  const { install, preinstall, postinstall, prepare, preprepare, postprepare, } = scripts;
75
77
  // Check for binding.gyp file (npm's implicit install detection)
@@ -1,4 +1,5 @@
1
1
  import { join } from 'node:path';
2
+ import { scriptsManifest } from "./scripts-manifest.js";
2
3
  /**
3
4
  * Checks if a node needs to be built based on the conditions from build.ts:
4
5
  * 1. Has install lifecycle scripts (install, preinstall, postinstall)
@@ -13,17 +14,18 @@ const nodeNeedsBuild = (node, scurry, packageJson) => {
13
14
  // If the manifest is not available on the node, read it from disk.
14
15
  // This can happen when the ideal graph is loaded from a lockfile
15
16
  // and there's no actual graph available to hydrate the manifest data from.
16
- let manifest = node.manifest;
17
- if (!manifest) {
18
- try {
19
- manifest = packageJson.read(node.resolvedLocation(scurry));
20
- node.manifest = manifest;
21
- }
22
- catch {
23
- // If the manifest cannot be read (missing/corrupted), treat as
24
- // "no build needed" to avoid failing the entire reification.
25
- return false;
26
- }
17
+ // An abbreviated registry manifest carries `hasInstallScript` in place
18
+ // of `scripts` and is likewise resolved from disk.
19
+ let manifest;
20
+ try {
21
+ const dir = node.resolvedLocation(scurry);
22
+ node.manifest ??= packageJson.read(dir);
23
+ manifest = scriptsManifest(node.manifest, dir, packageJson);
24
+ }
25
+ catch {
26
+ // If the manifest cannot be read (missing/corrupted), treat as
27
+ // "no build needed" to avoid failing the entire reification.
28
+ return false;
27
29
  }
28
30
  const { scripts = {} } = manifest;
29
31
  // Check for install lifecycle scripts
@@ -0,0 +1,8 @@
1
+ import type { PackageJson } from '@vltpkg/package-json';
2
+ import type { NormalizedManifest } from '@vltpkg/types';
3
+ /**
4
+ * The manifest to consult for lifecycle scripts. An abbreviated registry
5
+ * manifest replaces `scripts` with `hasInstallScript`, in which case the
6
+ * extracted package.json at `dir` is canonical.
7
+ */
8
+ export declare const scriptsManifest: (manifest: NormalizedManifest, dir: string, packageJson: PackageJson) => NormalizedManifest;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The manifest to consult for lifecycle scripts. An abbreviated registry
3
+ * manifest replaces `scripts` with `hasInstallScript`, in which case the
4
+ * extracted package.json at `dir` is canonical.
5
+ */
6
+ export const scriptsManifest = (manifest, dir, packageJson) => manifest.hasInstallScript && !manifest.scripts ?
7
+ packageJson.read(dir)
8
+ : manifest;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vltpkg/graph",
3
3
  "description": "A library that helps understanding & expressing what happens on an install",
4
- "version": "1.0.9",
4
+ "version": "1.1.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/vltpkg/vltpkg.git",
@@ -13,26 +13,26 @@
13
13
  "url": "http://vlt.sh"
14
14
  },
15
15
  "dependencies": {
16
- "@vltpkg/cmd-shim": "1.0.9",
17
- "@vltpkg/dep-id": "1.0.9",
18
- "@vltpkg/dss-breadcrumb": "1.0.9",
19
- "@vltpkg/error-cause": "1.0.9",
20
- "@vltpkg/fast-split": "1.0.9",
21
- "@vltpkg/graph-run": "1.0.9",
22
- "@vltpkg/init": "1.0.9",
23
- "@vltpkg/output": "1.0.9",
24
- "@vltpkg/package-info": "1.0.9",
25
- "@vltpkg/package-json": "1.0.9",
26
- "@vltpkg/pick-manifest": "1.0.9",
27
- "@vltpkg/query": "1.0.9",
28
- "@vltpkg/rollback-remove": "1.0.9",
29
- "@vltpkg/run": "1.0.9",
30
- "@vltpkg/satisfies": "1.0.9",
31
- "@vltpkg/security-archive": "1.0.9",
32
- "@vltpkg/spec": "1.0.9",
33
- "@vltpkg/types": "1.0.9",
34
- "@vltpkg/vlt-json": "1.0.9",
35
- "@vltpkg/workspaces": "1.0.9",
16
+ "@vltpkg/cmd-shim": "1.1.0",
17
+ "@vltpkg/dep-id": "1.1.0",
18
+ "@vltpkg/dss-breadcrumb": "1.1.0",
19
+ "@vltpkg/error-cause": "1.1.0",
20
+ "@vltpkg/fast-split": "1.1.0",
21
+ "@vltpkg/graph-run": "1.1.0",
22
+ "@vltpkg/init": "1.1.0",
23
+ "@vltpkg/output": "1.1.0",
24
+ "@vltpkg/package-info": "1.1.0",
25
+ "@vltpkg/package-json": "1.1.0",
26
+ "@vltpkg/pick-manifest": "1.1.0",
27
+ "@vltpkg/query": "1.1.0",
28
+ "@vltpkg/rollback-remove": "1.1.0",
29
+ "@vltpkg/run": "1.1.0",
30
+ "@vltpkg/satisfies": "1.1.0",
31
+ "@vltpkg/security-archive": "1.1.0",
32
+ "@vltpkg/spec": "1.1.0",
33
+ "@vltpkg/types": "1.1.0",
34
+ "@vltpkg/vlt-json": "1.1.0",
35
+ "@vltpkg/workspaces": "1.1.0",
36
36
  "path-scurry": "^2.0.1",
37
37
  "promise-call-limit": "^3.0.2"
38
38
  },