@vzn/vx-lockfile 0.0.594 → 0.0.596

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vzn/vx-lockfile",
3
- "version": "0.0.594",
3
+ "version": "0.0.596",
4
4
  "license": "MIT",
5
5
  "description": "Lockfile plugins for vx — pnpm(), bun(), npm(), yarn(): each keys every task on its project's own resolved dependency closure from the package manager's lockfile, so a lockfile change re-keys only the projects it reaches; --affected follows the same answer; `vx prune` cuts the workspace and the lockfile to a Docker subset.",
6
6
  "keywords": [
@@ -37,7 +37,7 @@
37
37
  "access": "public"
38
38
  },
39
39
  "peerDependencies": {
40
- "@vzn/vx": "^0.0.594"
40
+ "@vzn/vx": "^0.0.596"
41
41
  },
42
42
  "repository": {
43
43
  "type": "git",
package/src/blocks.ts CHANGED
@@ -19,8 +19,7 @@ export function pruneEntries(
19
19
  keep: (keyLine: string) => boolean,
20
20
  ): string[] {
21
21
  const pad = ' '.repeat(indent)
22
- const isKey = (l: string): boolean =>
23
- l.startsWith(pad) && l.length > indent && l[indent] !== ' ' && l[indent] !== '#'
22
+ const isKey = (l: string): boolean => l.startsWith(pad) && /^[^\s#]/.test(l.slice(indent))
24
23
  const head: string[] = []
25
24
  let i = from
26
25
  while (i < to && !isKey(lines[i]!)) head.push(lines[i++]!)
package/src/bun.ts CHANGED
@@ -11,6 +11,7 @@
11
11
  // Bun.JSONC is the parser: no dependency, and the file is Bun's own.
12
12
 
13
13
  import { reachDigests } from '@vzn/vx'
14
+ import { depsOf, record, type Json } from './json.js'
14
15
  import type { PruneScope } from './scope.js'
15
16
 
16
17
  export interface Lockfile {
@@ -35,7 +36,6 @@ export interface Entry {
35
36
  readonly resolution: string
36
37
  }
37
38
 
38
- type Json = Record<string, unknown>
39
39
  /** The top-level fields the digest reads per workspace. */
40
40
  // Read per workspace: the workspaces and packages themselves, and the fields
41
41
  // whose whole effect is the `packages` entry a workspace reaches — how a
@@ -51,13 +51,6 @@ const PER_WORKSPACE = new Set([
51
51
  'patchedDependencies',
52
52
  ])
53
53
 
54
- const DEP_FIELDS = [
55
- 'dependencies',
56
- 'devDependencies',
57
- 'optionalDependencies',
58
- 'peerDependencies',
59
- ] as const
60
-
61
54
  export function parseLockfile(text: string): Lockfile {
62
55
  let doc: unknown
63
56
  try {
@@ -110,20 +103,6 @@ export function parseLockfile(text: string): Lockfile {
110
103
  }
111
104
  }
112
105
 
113
- function depsOf(m: Json): ReadonlyMap<string, string> {
114
- const out = new Map<string, string>()
115
- for (const field of DEP_FIELDS) {
116
- const deps = record(m[field])
117
- if (deps === undefined) continue
118
- for (const [name, spec] of Object.entries(deps)) out.set(name, String(spec))
119
- }
120
- return out
121
- }
122
-
123
- function record(v: unknown): Json | undefined {
124
- return v !== null && typeof v === 'object' && !Array.isArray(v) ? (v as Json) : undefined
125
- }
126
-
127
106
  /**
128
107
  * Where dependency `name` of the package at node_modules path `from`
129
108
  * lives: the deepest `…/name` key up the path, then the root. A workspace
package/src/json.ts ADDED
@@ -0,0 +1,25 @@
1
+ export type Json = Record<string, unknown>
2
+
3
+ const DEP_FIELDS = [
4
+ 'dependencies',
5
+ 'devDependencies',
6
+ 'optionalDependencies',
7
+ 'peerDependencies',
8
+ ] as const
9
+
10
+ export function depsOf(
11
+ e: Json,
12
+ fields: readonly string[] = DEP_FIELDS,
13
+ ): ReadonlyMap<string, string> {
14
+ const out = new Map<string, string>()
15
+ for (const field of fields) {
16
+ const deps = record(e[field])
17
+ if (deps === undefined) continue
18
+ for (const [name, spec] of Object.entries(deps)) out.set(name, String(spec))
19
+ }
20
+ return out
21
+ }
22
+
23
+ export function record(v: unknown): Json | undefined {
24
+ return v !== null && typeof v === 'object' && !Array.isArray(v) ? (v as Json) : undefined
25
+ }
package/src/npm.ts CHANGED
@@ -8,6 +8,7 @@
8
8
  // ancestor directory's, else `node_modules/d` — Node's own walk.
9
9
 
10
10
  import { reachDigests } from '@vzn/vx'
11
+ import { depsOf, record, type Json } from './json.js'
11
12
  import type { PruneScope } from './scope.js'
12
13
 
13
14
  export interface Lockfile {
@@ -27,14 +28,6 @@ export interface Entry {
27
28
  readonly isWorkspace: boolean
28
29
  }
29
30
 
30
- type Json = Record<string, unknown>
31
- const DEP_FIELDS = [
32
- 'dependencies',
33
- 'devDependencies',
34
- 'optionalDependencies',
35
- 'peerDependencies',
36
- ] as const
37
-
38
31
  export function parseLockfile(text: string): Lockfile {
39
32
  let doc: unknown
40
33
  try {
@@ -74,20 +67,6 @@ export function parseLockfile(text: string): Lockfile {
74
67
  return { version, packages, global }
75
68
  }
76
69
 
77
- function depsOf(e: Json): ReadonlyMap<string, string> {
78
- const out = new Map<string, string>()
79
- for (const field of DEP_FIELDS) {
80
- const deps = record(e[field])
81
- if (deps === undefined) continue
82
- for (const [name, spec] of Object.entries(deps)) out.set(name, String(spec))
83
- }
84
- return out
85
- }
86
-
87
- function record(v: unknown): Json | undefined {
88
- return v !== null && typeof v === 'object' && !Array.isArray(v) ? (v as Json) : undefined
89
- }
90
-
91
70
  /**
92
71
  * Node's walk: `p/node_modules/name`, then the same under each ancestor
93
72
  * directory that is not itself a `node_modules`, then `node_modules/name`.
package/src/pnpm.ts CHANGED
@@ -13,6 +13,7 @@
13
13
 
14
14
  import { reachDigests } from '@vzn/vx'
15
15
  import { pruneSections } from './blocks.js'
16
+ import { record } from './json.js'
16
17
  import type { PruneScope } from './scope.js'
17
18
 
18
19
  export interface Lockfile {
@@ -59,11 +60,9 @@ export function parseLockfile(text: string): Lockfile {
59
60
  // with "regenerate it", which regenerates the same two documents.
60
61
  const parsed: unknown = Bun.YAML.parse(text)
61
62
  const docs = (Array.isArray(parsed) ? parsed : [parsed]).filter((d) => d !== null)
62
- const doc = docs.at(-1) as Yaml | undefined
63
+ const doc = record(docs.at(-1))
63
64
  const leading = docs.slice(0, -1)
64
- if (doc === undefined || typeof doc !== 'object' || Array.isArray(doc)) {
65
- throw new Error('pnpm-lock.yaml: not a YAML document')
66
- }
65
+ if (doc === undefined) throw new Error('pnpm-lock.yaml: not a YAML document')
67
66
  const version = scalar(doc['lockfileVersion'])
68
67
  const major = Number.parseInt(version, 10)
69
68
  if (!Number.isFinite(major) || major < 5) {
@@ -148,10 +147,6 @@ function scalar(v: unknown): string {
148
147
  : ''
149
148
  }
150
149
 
151
- function record(v: unknown): Yaml | undefined {
152
- return v !== null && typeof v === 'object' && !Array.isArray(v) ? (v as Yaml) : undefined
153
- }
154
-
155
150
  /** JSON with sorted keys, so YAML key order cannot move a digest. */
156
151
  export function stable(v: unknown): string {
157
152
  return JSON.stringify(v, (_k, val: unknown) =>
package/src/prune.ts CHANGED
@@ -25,6 +25,7 @@ import {
25
25
  type ProjectMeta,
26
26
  } from '@vzn/vx'
27
27
  import * as bunLock from './bun.js'
28
+ import { record } from './json.js'
28
29
  import * as npmLock from './npm.js'
29
30
  import * as pnpmLock from './pnpm.js'
30
31
  import * as yarnLock from './yarn.js'
@@ -317,9 +318,7 @@ async function namedFiles(root: string, manifest: Record<string, unknown>): Prom
317
318
  const p = path.join(root, file)
318
319
  if (!(await exists(p))) return {}
319
320
  const doc: unknown = Bun.YAML.parse(await Bun.file(p).text())
320
- return doc !== null && typeof doc === 'object' && !Array.isArray(doc)
321
- ? (doc as Record<string, unknown>)
322
- : {}
321
+ return record(doc) ?? {}
323
322
  }
324
323
  named.push(...values((await yaml('pnpm-workspace.yaml'))['patchedDependencies']))
325
324
  const yarnrc = await yaml('.yarnrc.yml')
package/src/yarn.ts CHANGED
@@ -15,6 +15,7 @@ import path from 'node:path'
15
15
  import { reachDigests } from '@vzn/vx'
16
16
  import { stable } from './pnpm.js'
17
17
  import { pruneEntries, yamlKey } from './blocks.js'
18
+ import { depsOf, record } from './json.js'
18
19
  import type { PruneScope } from './scope.js'
19
20
 
20
21
  export interface Lockfile {
@@ -45,8 +46,6 @@ export interface Entry {
45
46
  readonly resolution: string
46
47
  }
47
48
 
48
- type Json = Record<string, unknown>
49
-
50
49
  export function parseLockfile(text: string): Lockfile {
51
50
  const head = text.slice(0, 400)
52
51
  if (/^# yarn lockfile v1/m.test(head)) return parseClassic(text)
@@ -196,20 +195,6 @@ function unquote(s: string): string {
196
195
  return s.length >= 2 && s.startsWith('"') && s.endsWith('"') ? s.slice(1, -1) : s
197
196
  }
198
197
 
199
- function depsOf(e: Json, fields: readonly string[]): ReadonlyMap<string, string> {
200
- const out = new Map<string, string>()
201
- for (const field of fields) {
202
- const deps = record(e[field])
203
- if (deps === undefined) continue
204
- for (const [name, spec] of Object.entries(deps)) out.set(name, String(spec))
205
- }
206
- return out
207
- }
208
-
209
- function record(v: unknown): Json | undefined {
210
- return v !== null && typeof v === 'object' && !Array.isArray(v) ? (v as Json) : undefined
211
- }
212
-
213
198
  /**
214
199
  * `bar` + `npm:^2` → the entry keyed `bar@npm:^2`; classic: `bar@^2`. A
215
200
  * bare range gets berry's `npm:` prefix. A `workspace:` range resolves to