@vzn/vx-lockfile 0.0.596 → 0.0.598

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/README.md CHANGED
@@ -41,7 +41,7 @@ A lockfile the parser cannot read **refuses the run**, naming the file, the reas
41
41
 
42
42
  ## Cost
43
43
 
44
- The claim, the per-project key, the memo and the `--affected` diff are core's `lockfileClaim`; this package is the parsers, and they are internal: it exports `pnpm`, `bun`, `npm`, `yarn` and `LockfileOptions`. A lockfile is parsed **once per content**: the digests are memoised under the cache dir (`lockfile-claims/<file>.json`) by the file's xxh3, so a warm run pays one read, one hash and one small JSON read — never a parse — and the read happens once per run, not per task. The digest is one hash per strongly connected component of the dependency graph (lockfiles carry cycles), children first, so a 1000-importer / 3000-package lockfile digests in ~20 ms when it does change.
44
+ The claim, the per-project key, the memo and the `--affected` diff are core's `lockfileClaim`; this package is the parsers, and they are internal: it exports `pnpm`, `bun`, `npm`, `yarn` and `LockfileOptions`. A lockfile is parsed **once per content**: the digests are memoised under the cache dir (`lockfile-claims/<file>.json`) by the file's xxh3 and the claimant, so a warm run pays one read, one hash and one small JSON read — never a parse — and the read happens once per run, not per task. The digest is one hash per strongly connected component of the dependency graph (lockfiles carry cycles), children first, so a 1000-importer / 3000-package lockfile digests in ~20 ms when it does change.
45
45
 
46
46
  ## `--affected`
47
47
 
@@ -55,7 +55,7 @@ Declaring any of the four plugins adds `vx prune` (the `commands` seam): the wor
55
55
  vx prune <project...> [--out-dir <dir>] [--docker]
56
56
  ```
57
57
 
58
- The out dir (default `out/`, relative to the cwd) gets the root `package.json` with `workspaces` rewritten to the subset's dirs, `pnpm-workspace.yaml` with `packages` rewritten (every other key as written), each lockfile at the root **pruned** to what the subset installs, the install config (`.npmrc`, `.yarnrc.yml`, `.pnpmfile.cjs`, `bunfig.toml`, `.nvmrc`, `.node-version`, the patch files `patchedDependencies` names, Yarn's `yarnPath` and plugins), `vx.workspace.*`, the root `vx.config.*`, and each project directory less `node_modules`, `.git`, `.vx` and `.turbo`. A workspace package a copied vx config imports (a local plugin) comes along with its closure: the config loads before any task. A relative config import that leaves the subset is warned about. `--docker` writes `json/` — the root install files and each project's `package.json`, the cacheable install layer — and `full/`, everything:
58
+ The out dir (default `out/`, relative to the cwd) gets the root `package.json` with `workspaces` rewritten to the subset's dirs (a glob character in a dir name bracketed, `a[1]` → `a[[]1]`, so the pattern matches that dir alone), `pnpm-workspace.yaml` with `packages` rewritten (every other key as written), each lockfile at the root **pruned** to what the subset installs, the install config (`.npmrc`, `.yarnrc.yml`, `.pnpmfile.cjs`, `bunfig.toml`, `.nvmrc`, `.node-version`, the patch files `patchedDependencies` names, Yarn's `yarnPath` and plugins), `vx.workspace.*`, the root `vx.config.*`, and each project directory less `node_modules`, `.git`, `.vx` and `.turbo`. A workspace package a copied vx config imports (a local plugin) comes along with its closure: the config loads before any task. A relative config import that leaves the subset is warned about. `--docker` writes `json/` — the root install files and each project's `package.json`, the cacheable install layer — and `full/`, everything:
59
59
 
60
60
  ```dockerfile
61
61
  COPY out/json/ .
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vzn/vx-lockfile",
3
- "version": "0.0.596",
3
+ "version": "0.0.598",
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.596"
40
+ "@vzn/vx": "^0.0.598"
41
41
  },
42
42
  "repository": {
43
43
  "type": "git",
package/src/prune.ts CHANGED
@@ -195,7 +195,8 @@ export async function prune(argv: readonly string[], ctx: CommandContext): Promi
195
195
  const listed = Array.isArray(field)
196
196
  ? (field as string[])
197
197
  : ((field as { packages?: string[] } | undefined)?.packages ?? undefined)
198
- const workspaces = listed?.includes('.') ? ['.', ...rels] : rels
198
+ const patterns = rels.map(literalGlob)
199
+ const workspaces = listed?.includes('.') ? ['.', ...patterns] : patterns
199
200
  if (listed !== undefined) {
200
201
  rootManifest['workspaces'] = Array.isArray(field)
201
202
  ? workspaces
@@ -237,7 +238,7 @@ export async function prune(argv: readonly string[], ctx: CommandContext): Promi
237
238
  if (await exists(workspaceYaml)) {
238
239
  written.set(
239
240
  'pnpm-workspace.yaml',
240
- rewriteWorkspaceYaml(await Bun.file(workspaceYaml).text(), rels),
241
+ rewriteWorkspaceYaml(await Bun.file(workspaceYaml).text(), patterns),
241
242
  )
242
243
  }
243
244
  // A manifest with no `workspaces` (pnpm's) is copied byte for byte.
@@ -287,10 +288,21 @@ export async function prune(argv: readonly string[], ctx: CommandContext): Promi
287
288
  return 0
288
289
  }
289
290
 
290
- /** `packages:` cut to the subset's dirs; every other key as written. */
291
- function rewriteWorkspaceYaml(text: string, rels: readonly string[]): string {
291
+ /**
292
+ * A dir as a workspace pattern that matches only itself: every package
293
+ * manager and vx read the list as globs, and `packages/a[1]` matched
294
+ * `packages/a1`, so the pruned copy had no such member. A class of one
295
+ * (`[[]`) is the escape bun, npm, pnpm, yarn and `Bun.Glob` all read;
296
+ * a backslash is not (bun found no workspace).
297
+ */
298
+ function literalGlob(rel: string): string {
299
+ return rel.replace(/[*?[{]/g, '[$&]')
300
+ }
301
+
302
+ /** `packages:` cut to the subset's member patterns; every other key as written. */
303
+ function rewriteWorkspaceYaml(text: string, members: readonly string[]): string {
292
304
  const lines = text.split('\n')
293
- const list = ['packages:', ...rels.map((r) => ` - ${JSON.stringify(r)}`)]
305
+ const list = ['packages:', ...members.map((r) => ` - ${JSON.stringify(r)}`)]
294
306
  const at = lines.findIndex((l) => /^packages\s*:/.test(l))
295
307
  if (at === -1) return [...list, ...lines].join('\n')
296
308
  let end = at + 1