@antongolub/lockfile 0.0.0-snapshot.43 → 0.0.0-snapshot.45

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 (65) hide show
  1. package/README.md +130 -202
  2. package/SCHEMAS.md +120 -0
  3. package/dist/_npm-flat-types-5XRp-_Te.d.ts +14 -0
  4. package/dist/_pnpm-flat-core-DtT-PfX-.d.ts +37 -0
  5. package/dist/_yarn-berry-core-nexIf1L1.d.ts +16 -0
  6. package/dist/complete.d.ts +68 -0
  7. package/dist/complete.js +298 -0
  8. package/dist/formats/bun-text.d.ts +34 -0
  9. package/dist/formats/bun-text.js +1405 -0
  10. package/dist/formats/npm-1.d.ts +34 -0
  11. package/dist/formats/npm-1.js +1657 -0
  12. package/dist/formats/npm-2.d.ts +24 -0
  13. package/dist/formats/npm-2.js +1961 -0
  14. package/dist/formats/npm-3.d.ts +24 -0
  15. package/dist/formats/npm-3.js +1733 -0
  16. package/dist/formats/pnpm-v5.d.ts +38 -0
  17. package/dist/formats/pnpm-v5.js +2114 -0
  18. package/dist/formats/pnpm-v6.d.ts +28 -0
  19. package/dist/formats/pnpm-v6.js +2640 -0
  20. package/dist/formats/pnpm-v9.d.ts +28 -0
  21. package/dist/formats/pnpm-v9.js +2640 -0
  22. package/dist/formats/yarn-berry-v4.d.ts +24 -0
  23. package/dist/formats/yarn-berry-v4.js +2297 -0
  24. package/dist/formats/yarn-berry-v5.d.ts +24 -0
  25. package/dist/formats/yarn-berry-v5.js +2292 -0
  26. package/dist/formats/yarn-berry-v6.d.ts +24 -0
  27. package/dist/formats/yarn-berry-v6.js +2292 -0
  28. package/dist/formats/yarn-berry-v7.d.ts +24 -0
  29. package/dist/formats/yarn-berry-v7.js +2292 -0
  30. package/dist/formats/yarn-berry-v8.d.ts +24 -0
  31. package/dist/formats/yarn-berry-v8.js +2293 -0
  32. package/dist/formats/yarn-berry-v9.d.ts +24 -0
  33. package/dist/formats/yarn-berry-v9.js +2293 -0
  34. package/dist/formats/yarn-classic.d.ts +34 -0
  35. package/dist/formats/yarn-classic.js +1634 -0
  36. package/dist/graph-DbCmOfBk.d.ts +155 -0
  37. package/dist/index.d.ts +48 -0
  38. package/dist/index.js +8324 -0
  39. package/dist/modify-Qsze2kCh.d.ts +218 -0
  40. package/dist/modify.d.ts +20 -0
  41. package/dist/modify.js +988 -0
  42. package/dist/registry.d.ts +60 -0
  43. package/dist/registry.js +649 -0
  44. package/dist/types-Ci06KZkZ.d.ts +46 -0
  45. package/package.json +120 -62
  46. package/target/cjs/index.cjs +0 -1096
  47. package/target/cjs/vendor.cjs +0 -8500
  48. package/target/dts/analyze.d.ts +0 -7
  49. package/target/dts/cli.d.ts +0 -11
  50. package/target/dts/common.d.ts +0 -28
  51. package/target/dts/convert.d.ts +0 -3
  52. package/target/dts/format.d.ts +0 -2
  53. package/target/dts/formats/npm-1.d.ts +0 -24
  54. package/target/dts/formats/npm-2.d.ts +0 -16
  55. package/target/dts/formats/npm-3.d.ts +0 -36
  56. package/target/dts/formats/yarn-berry.d.ts +0 -22
  57. package/target/dts/formats/yarn-classic.d.ts +0 -16
  58. package/target/dts/index.d.ts +0 -7
  59. package/target/dts/interface.d.ts +0 -90
  60. package/target/dts/parse.d.ts +0 -3
  61. package/target/dts/util.d.ts +0 -11
  62. package/target/dts/vendor.d.ts +0 -3
  63. package/target/esm/cli.mjs +0 -77
  64. package/target/esm/index.mjs +0 -1017
  65. package/target/esm/vendor.mjs +0 -8458
package/README.md CHANGED
@@ -1,238 +1,166 @@
1
1
  # @antongolub/lockfile
2
- > Read and write lockfiles with reasonable losses
3
2
 
4
- <p><img alt="@antongolub/lockfile" src="./pics/pic.png" align="right" width="300">
5
- Each package manager brings its own philosophy of how to describe, store and control project dependencies.
6
- It <i>seems</i> acceptable for developers, but literally becomes a <strike>pain in *** ***</strike> headache for isec, devops and release engineers.
7
- This lib is a naive attempt to build a pm-independent, generic, extensible and reliable deps representation.
3
+ > Universal lockfile model and converter for **npm**, **yarn**, **pnpm**, **bun**.
4
+
5
+ <p><img alt="@antongolub/lockfile universal lockfile model and converter for npm, yarn, pnpm, bun" src="./pics/lockfile.svg" align="right" width="300">
6
+
7
+ Each package manager brings its own philosophy of how to describe, store and
8
+ control project dependencies. It looks acceptable to a developer staring at a
9
+ single repo, but it becomes a real headache for IS, DevOps and release
10
+ engineers — and impossible for any tool that needs to reason about
11
+ dependency graphs across the ecosystem.
12
+
13
+ This library models the dependency graph independent of any specific
14
+ package manager, then projects it back into the format you need.
15
+ Conversion is one use case; modification (audit-fix, override pinning,
16
+ license filtering) is the headline.
8
17
 
9
- The `package.json` manifest contains its own deps requirements, the `lockfile` holds the deps resolution snapshot<sup>*</sup>,
10
- so both of them are required to build a dependency graph. We can try to convert this data into a normalized representation for further analysis and processing (for example, to fix vulnerabilities).
11
- And then, if necessary, try convert it back to the original/another format.
12
18
  </p>
13
19
 
14
20
  ## Status
15
- Proof of concept. The API may change significantly ⚠️
16
21
 
17
- ## Getting started
18
- ### Install
19
- ```shell
20
- yarn add @antongolub/lockfile@snapshot
21
- ```
22
+ 🔒 **Contract preview, implementation in progress.** The public API
23
+ (`parse` / `stringify`) is locked. Adapter implementations are landing
24
+ incrementally — see [SCHEMAS.md](./SCHEMAS.md) for what's recognised.
25
+ Not yet published; `npm install` will appear once the first adapters
26
+ ship end-to-end.
22
27
 
23
- ## Usage
24
- _tl;dr_
25
- ```ts
26
- import fs from 'fs/promises'
27
- import {parse, analyze} from '@antongolub/lockfile'
28
+ ## Concept
28
29
 
29
- const lf = await fs.readFile('yarn.lock', 'utf-8')
30
- const pkg = await fs.readFile('package.json', 'utf-8')
30
+ A target lockfile is **constructed** from facts gathered across whatever
31
+ sources are available: the input lockfile bytes, project `package.json`s,
32
+ the package-manager cache, and (opt-in) the registry. The simplest case is
33
+ *conversion* — parse one format, stringify another. The general case is
34
+ *construction*: assemble what the target requires from whichever source can
35
+ supply it.
31
36
 
32
- const snapshot = parse(lf, pkg) // Holds JSON-friendly TEntries[]
33
- const idx = analyze(snapshot) // An index to represent repo dep graphs
37
+ Three layers, never collapsed:
34
38
 
35
- // idx.entries
36
- // idx.prod
37
- // idx.edges
38
- ```
39
+ - **Manifest** — declared constraints from `package.json`(s).
40
+ - **Graph** — resolved package instances (peer-aware) and the edges
41
+ between them. The canonical internal model. Modifiers operate here.
42
+ - **Layout** — physical projection on disk: hoisted, isolated (pnpm-style),
43
+ PnP, nm-linked.
44
+
45
+ Conversion is **lossy by design**. We aim for *semantically equivalent*,
46
+ not *byte-identical*. Irreducible facts (integrity hashes, resolution URLs,
47
+ signatures) are the exception — they are never silently lost.
39
48
 
40
49
  ## API
41
- ### JS/TS
42
- ```ts
43
- import { parse, format, analyze, convert } from '@antongolub/lockfile'
44
50
 
45
- const lf = await fs.readFile('yarn.lock', 'utf-8')
46
- const pkgJson = await fs.readFile('package.json', 'utf-8')
47
- const snapshot = parse(lf, pkgJson)
51
+ ```ts
52
+ import { parse, stringify } from '@antongolub/lockfile'
48
53
 
49
- const lf1 = format(snapshot)
50
- const lf2 = format(snapshot, 'npm-1') // Throws err: npm v1 meta does not support workspaces
54
+ const lf = parse(rawLockfileBytes)
55
+ const str = stringify(lf, { format: 'npm-3' })
56
+ ```
51
57
 
52
- const meta = await readMeta() // reads local package.jsons data to gather required data like `engines`, `license`, `bins`, etc
53
- const meta2 = await fetchMeta(snapshot) // does the same, but from the remote registry
54
- const lf3 = format(snapshot, 'npm-3', {meta}) // format with options
58
+ Two top-level operations, modelled on `JSON.parse` / `JSON.stringify`:
55
59
 
56
- const idx = analyze(snapshot)
57
- idx.edges
58
- // [
59
- // [ '', '@antongolub/npm-test@4.0.1' ],
60
- // [ '@antongolub/npm-test@4.0.1', '@antongolub/npm-test@3.0.1' ],
61
- // [ '@antongolub/npm-test@3.0.1', '@antongolub/npm-test@2.0.1' ],
62
- // [ '@antongolub/npm-test@2.0.1', '@antongolub/npm-test@1.0.0' ]
63
- // ]
60
+ ```ts
61
+ parse(input: string | Uint8Array, options?: ParseOptions): Lockfile
64
62
 
65
- const lf4 = await convert(lf, pkgJson, 'yarn-berry')
63
+ stringify(lockfile: Lockfile, options: StringifyOptions): string
66
64
  ```
67
65
 
68
- ### CLI
69
- ```shell
70
- npx @antongolub/lockfile@snapshot <cmd> [options]
66
+ - `parse` auto-detects the format by content sniffing. Pass
67
+ `{ format: '<id>' }` to skip detection. Pass `{ manifests }` for
68
+ formats that need extra workspace context (notably `yarn-classic`).
69
+ - `stringify`'s `options.format` is **required** — there is no implicit
70
+ "same as parsed". Round-tripping is an explicit choice the caller makes.
71
71
 
72
- npx @antongolub/lockfile@snapshot parse --input=yarn.lock,package.json --output=snapshot.json
73
- npx @antongolub/lockfile@snapshot format --input=snapshot.json --output=yarn.lock
74
- ```
72
+ `Lockfile` is the public alias for the internal canonical-graph type.
73
+ `FormatId` is a string-literal union — see
74
+ [SCHEMAS.md](./SCHEMAS.md) for the full list.
75
+
76
+ ### Options
75
77
 
76
- | Command / Option | Description |
77
- |------------------|---------------------------------------------------------------------------------------|
78
- | `parse` | Parses lockfiles and package manifests into a snapshot |
79
- | `format` | Formats a snapshot into a lockfile |
80
- | `convert` | Converts a lockfile into another format. Shortcut for `parse` + `format` |
81
- | `--input` | A comma-separated list of files to parse: `snapshot.json` or `yarn.lock,package.json` |
82
- | `--output` | A file to write the result to: `snapshot.json` or `yarn.lock` |
83
- | `--format` | A lockfile format: `npm-1`, `npm-2`, `npm-3`, `yarn-berry`, `yarn-classic` |
84
-
85
- ### Terms
86
- `nmtree` — fs projection of deps, directories structure
87
- `deptree` — bounds full dep paths with their resolved packages
88
- `depgraph` — describes how resolved pkgs are related with each other
89
-
90
- ### Lockfiles types
91
- | Package manager | Meta format | Read | Write |
92
- |----------------------|-------------|------|-------|
93
- | npm <7 | 1 | ✓ | ✓ |
94
- | npm >=7 | 2 | ✓ | |
95
- | npm >=9 | 3 | ✓ | |
96
- | yarn 1 (classic) | 1 | ✓ | ✓ |
97
- | yarn 2, 3, 4 (berry) | 5, 6, 7 | ✓ | ✓ |
98
-
99
- ### Dependency protocols
100
- | Type | Supported | Example | Description |
101
- |-----------|-----------|-----------------------------------------|----------------------------------------------------------------|
102
- | semver | ✓ | `^1.2.3` | Resolves from the default registry |
103
- | tag | | `latest` | Resolves from the default registry |
104
- | npm | ✓ | `npm:name@...` | Resolves from the npm registry |
105
- | git | | `git@github.com:foo/bar.git` | Downloads a public package from a Git repository |
106
- | github | | `github:foo/bar` | Downloads a public package from GitHub |
107
- | github | ✓ | `foo/bar` | Alias for the github: protocol |
108
- | file | | `file:./my-package` | Copies the target location into the cache |
109
- | link | | `link:./my-folder` | Creates a link to the ./my-folder folder (ignore dependencies) |
110
- | patch | _limited_ | `patch:left-pad@1.0.0#./my-patch.patch` | Creates a patched copy of the original package |
111
- | portal | | `portal:./my-folder` | Creates a link to the ./my-folder folder (follow dependencies) |
112
- | workspace | _limited_ | `workspace:*` | Creates a link to a package in another workspace |
113
-
114
- https://v3.yarnpkg.com/features/protocols
115
- https://yarnpkg.com/protocols
116
- https://docs.npmjs.com/cli/v10/configuring-npm/package-json#dependencies
117
-
118
- ### `TSnapshot`
119
78
  ```ts
120
- export type TSnapshot = Record<string, TEntry>
121
-
122
- export type TEntry = {
123
- name: string
124
- version: string
125
- ranges: string[]
126
- hashes: {
127
- sha512?: string
128
- sha256?: string
129
- sha1?: string
130
- checksum?: string
131
- md5?: string
132
- }
133
- source: {
134
- type: TSourceType // npm, workspace, gh, patch, etc
135
- id: string
136
- registry?: string
137
- }
138
- // optional pm-specific lockfile meta
139
- manifest?: TManifest
140
- conditions?: string
141
- dependencies?: TDependencies
142
- dependenciesMeta?: TDependenciesMeta
143
- devDependencies?: TDependencies
144
- optionalDependencies?: TDependencies
145
- peerDependencies?: TDependencies
146
- peerDependenciesMeta?: TDependenciesMeta
147
- bin?: Record<string, string>
148
- engines?: Record<string, string>
149
- funding?: Record<string, string>
79
+ type ParseOptions = {
80
+ format?: FormatId // skip auto-detect
81
+ manifests?: Manifests // package.jsons keyed by workspace path
82
+ pmConfig?: PmConfig // .npmrc / .yarnrc.yml / pnpm-workspace.yaml / bunfig.toml
83
+ installDir?: string // path to node_modules / .pnp.cjs (refinement)
84
+ cache?: CacheAdapter // PM cache (refinement)
85
+ registry?: RegistryAdapter // network access (opt-in)
150
86
  }
151
- ```
152
87
 
153
- ### `TSnapshotIndex`
154
- ```ts
155
- export interface TSnapshotIndex {
156
- snapshot: TSnapshot
157
- entries: TEntry[]
158
- roots: TEntry[]
159
- edges: [string, string][]
160
- tree: Record<string, {
161
- key: string
162
- chunks: string[]
163
- parents: TEntry[]
164
- id: string
165
- name: string
166
- version: string
167
- entry: TEntry
168
- depth: number // the lowest level where the dep@ver first time occurs
169
- }>
170
- prod: Set<TEntry>
171
- getEntryId ({name, version}: TEntry): string
172
- getEntry (name: string, version?: string): TEntry | undefined,
173
- getEntryByRange (name: string, range: string): TEntry | undefined
174
- getEntryDeps(entry: TEntry): TEntry[]
88
+ type StringifyOptions = {
89
+ format: FormatId // required
90
+ manifests?: Manifests
91
+ pmConfig?: PmConfig
92
+ installDir?: string
93
+ cache?: CacheAdapter
94
+ registry?: RegistryAdapter
95
+ onDiagnostic?: (d: Diagnostic) => void
175
96
  }
176
97
  ```
177
98
 
178
- ### Caveats
179
- * There is an infinite number of `nmtrees` that corresponds to the specified `deptree`, but among them there is a finite set of effective (sufficient) for the target criterion — for example, nesting, size, homogeneity of versions
180
- * npm1: `optional: true` label is not supported yet
181
- * yarn berry: no idea how to resolve and inject PnP patches https://github.com/yarnpkg/berry/tree/master/packages/plugin-compat
182
- * npm2 and npm3 requires `engines` and `funding` data, while yarn* or npm1 does not contain it
183
- * many `nmtree` projections may correspond to the specified `depgraph`
184
- * pkg.json `resolutions` and `overrides` directives are completely ignored for now
185
- * pkg aliases are not _fully_ supported yet [#2](https://github.com/antongolub/lockfile/issues/2#issuecomment-1786613893)
186
-
187
- ### Snippets
188
- Extracts all deps by depth:
99
+ `pmConfig` / `installDir` / `cache` / `registry` are progressive
100
+ **refinement opt-ins**: each unlocks more information at higher cost. The
101
+ default succeeds offline, against the lockfile bytes (and `manifests`)
102
+ alone.
103
+
104
+ ### Sub-imports
105
+
106
+ | Surface | Importable as | Contains |
107
+ |---------|---------------|----------|
108
+ | Root | `@antongolub/lockfile` | `parse`, `stringify`, plus types: `Lockfile`, `FormatId`, `ParseOptions`, `StringifyOptions`, `Manifest`, `Manifests` |
109
+ | Modifiers | `@antongolub/lockfile/modify` | audit-fix, override-pin, license-filter |
110
+ | Registry | `@antongolub/lockfile/registry` | adapters for live npm, file cache, frozen-from-lockfile |
111
+ | Per-format | `@antongolub/lockfile/formats/<id>` | direct access to a single adapter (test surface; not a primary user API) |
112
+
113
+ ### Errors
114
+
115
+ `parse` / `stringify` throw a single `LockfileError` discriminated by
116
+ `code`:
117
+
189
118
  ```ts
190
- const getDepsByDepth = (idx: TSnapshotIndex, depth = 0) => Object.values(idx.tree)
191
- .filter(({depth: d}) => d === depth)
192
- .map(({entry}) => entry)
119
+ 'PARSE_FAILED' | 'FORMAT_DETECT_FAILED' | 'FORMAT_MISMATCH'
120
+ | 'CAPABILITY_LACK' | 'MISSING_MANIFEST'
121
+ | 'IRREDUCIBLE_LOSS' | 'INVARIANT_VIOLATION'
193
122
  ```
194
123
 
195
- Get the longest dep chain:
196
- ```ts
197
- const getLongestChain = (): TEntry[] => {
198
- let max = 0
199
- let chain: TEntry[] = []
200
-
201
- for (const e of Object.values(idx.tree)) {
202
- if (e.depth > max) {
203
- max = e.depth
204
- chain = [...e.parents, e.entry]
205
- }
206
- }
207
- return chain
208
- }
124
+ Reducible losses (e.g. dropped patches when emitting `npm-1` from a
125
+ yarn-berry source) surface as `Diagnostic` events via the
126
+ `onDiagnostic` callback, not exceptions.
209
127
 
210
- constole.log(
211
- getLongestChain()
212
- .map((e) => idx.getEntryId(e))
213
- .join(' -> ')
214
- )
215
- ```
128
+ ## Schemas
129
+
130
+ Every recognised lockfile schema is enumerated in
131
+ [SCHEMAS.md](./SCHEMAS.md), with adapter ids, the schema-marker each
132
+ carries, the package-manager versions that emit it by default, and
133
+ permalinked sources. Use that table as the index when calling
134
+ `parse({ format })` or `stringify({ format })`.
216
135
 
217
- ### Inspired by
218
- * [synp](https://github.com/imsnif/synp)
219
- * [snyk-nodejs-lockfile-parser](https://github.com/snyk/nodejs-lockfile-parser)
220
- * [yarn](https://github.com/yarnpkg/yarn/blob/master/src/lockfile/parse.js)
221
- * [yarn-lockfile](https://github.com/yarnpkg/yarn/tree/master/packages/lockfile)
222
-
223
- ### Refs
224
- * [yarn.lock](https://classic.yarnpkg.com/en/docs/yarn-lock/)
225
- * [package-lock-json](https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json)
226
- * [what-is-package-lock-json](https://snyk.io/blog/what-is-package-lock-json/)
227
- * [the-ultimate-guide-to-yarn-lock-lockfiles](https://www.arahansen.com/the-ultimate-guide-to-yarn-lock-lockfiles/)
228
- * [package-lock-json-the-complete-guide](https://medium.com/helpshift-engineering/package-lock-json-the-complete-guide-2ae40175ebdd)
229
- <details>
230
- <summary>more</summary>
231
-
232
- * [cvent/pnpm-lock-export](https://github.com/cvent/pnpm-lock-export)
233
- * [why-keep-package-lockjson](https://blog.npmjs.org/post/621733939456933888/npm-v7-series-why-keep-package-lockjson.html)
234
- * [pnpm/lockfile-utils](https://github.com/pnpm/pnpm/tree/main/lockfile/lockfile-utils)
235
- </details>
136
+ ## Predecessor and inspirations
137
+
138
+ This project is the architectural successor to
139
+ [`yarn-audit-fix`](https://github.com/antongolub/yarn-audit-fix), generalised
140
+ beyond yarn.
141
+
142
+ Earlier work in this space:
143
+
144
+ - [synp](https://github.com/imsnif/synp)
145
+ - [snyk-nodejs-lockfile-parser](https://github.com/snyk/nodejs-lockfile-parser)
146
+ - [`@yarnpkg/lockfile`](https://github.com/yarnpkg/yarn/tree/master/packages/lockfile)
147
+ - [`pnpm/lockfile-utils`](https://github.com/pnpm/pnpm/tree/main/lockfile)
148
+
149
+ ## Package-manager docs
150
+
151
+ - [`package-lock.json`](https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json)
152
+ npm
153
+ - [yarn lockfile (classic)](https://classic.yarnpkg.com/lang/en/docs/yarn-lock/)
154
+ / [yarn lockfile (berry)](https://github.com/yarnpkg/berry/blob/master/packages/yarnpkg-core/sources/Project.ts)
155
+ - [`pnpm/spec/lockfile/`](https://github.com/pnpm/spec/tree/master/lockfile)
156
+ — pnpm
157
+ - [bun lockfile](https://bun.com/docs/pm/lockfile) — bun
158
+
159
+ ## Compatibility
160
+
161
+ - **Node ≥ 20.** No browser build planned.
162
+ - **ESM only.** Consumers on CommonJS use dynamic `await import(…)`.
236
163
 
237
164
  ## License
165
+
238
166
  [MIT](./LICENSE)
package/SCHEMAS.md ADDED
@@ -0,0 +1,120 @@
1
+ # Lockfile schemas
2
+
3
+ Public reference for every lockfile schema this project recognises:
4
+ how to identify each, which package-manager versions emit it by
5
+ default, and which can install from it. Adapter ids match the
6
+ `FormatId` literal accepted by `parse({ format })` and required by
7
+ `stringify({ format })`.
8
+
9
+ ## npm
10
+
11
+ | Adapter id | Marker | Default writer | Reader |
12
+ |------------|--------|----------------|--------|
13
+ | `npm-1` | `lockfileVersion: 1` | npm `>=5 <7` | npm `>=5` |
14
+ | `npm-2` | `lockfileVersion: 2` | npm `>=7 <9` | npm `>=7` |
15
+ | `npm-3` | `lockfileVersion: 3` | npm `>=9` | npm `>=7` |
16
+
17
+ `npm install --lockfile-version=N` overrides the writer choice within
18
+ the supported range.
19
+
20
+ ## yarn
21
+
22
+ `yarn-classic` and `yarn-berry-*` use different lockfile schemas. The
23
+ "v" suffix on berry adapters is `__metadata.version`. Yarn classic
24
+ uses a `# yarn lockfile v1` *comment header* instead — unrelated to
25
+ berry's `__metadata`.
26
+
27
+ | Adapter id | Marker | Default writer | Reader |
28
+ |-------------------|------------------------------|----------------------|---------|
29
+ | `yarn-classic` | `# yarn lockfile v1` header | yarn `>=1 <2` | yarn `>=1 <2` (native); yarn `>=2` via `yarn import` |
30
+ | `yarn-berry-v3` | `__metadata.version: 3` | yarn `>=2.0.0-rc.4 <2.0.0-rc.20` (pre-release only) | yarn `>=2` |
31
+ | `yarn-berry-v4` | `__metadata.version: 4` | yarn `>=2.0.0-rc.20 <3.1` | yarn `>=2` |
32
+ | `yarn-berry-v5` | `__metadata.version: 5` | yarn `=3.1.0` (one minor) | yarn `>=3.1` |
33
+ | `yarn-berry-v6` | `__metadata.version: 6` | yarn `>=3.2 <4` | yarn `>=3.2` |
34
+ | `yarn-berry-v8` | `__metadata.version: 8` | yarn `>=4.0 <4.14` | yarn `>=4` |
35
+ | `yarn-berry-v9` | `__metadata.version: 9` | yarn `>=4.14` | yarn `>=4.14` |
36
+
37
+ **Schema numbers that don't exist:**
38
+ - `__metadata.version: 1` and `2` were never used by berry.
39
+ - `__metadata.version: 7` was skipped — yarn went `6 → 8` in 4.0.0.
40
+
41
+ `YARN_LOCKFILE_VERSION_OVERRIDE` (yarn 4+) lets one binary write any
42
+ schema version it can read; structural fidelity to the canonical
43
+ writer is not guaranteed.
44
+
45
+ ## pnpm
46
+
47
+ | Adapter id | Marker | Default writer |
48
+ |------------|--------------------------|----------------------|
49
+ | `pnpm-v5` | `lockfileVersion: 5.x` | pnpm `>=3 <8` (pnpm 7 stayed on `5.4` by default) |
50
+ | `pnpm-v6` | `lockfileVersion: '6.0'`/`'6.1'` | pnpm `>=8 <9` |
51
+ | `pnpm-v9` | `lockfileVersion: '9.0'` | pnpm `>=9` |
52
+
53
+ **Schema numbers that don't exist:** `7` and `8`. pnpm 9 jumped
54
+ straight from `6.x` to `9.0`.
55
+
56
+ ## bun
57
+
58
+ | Adapter id | Marker | Default writer | Status |
59
+ |---------------|---------------------------------|----------------|--------|
60
+ | `bun-text` | `bun.lock` filename + JSONC | bun `>=1.2` | primary bun target |
61
+ | `bun-binary` | `bun.lockb` filename + magic | bun `<1.2` | detect-only — not parsed |
62
+
63
+ `bun-binary` is a **permanent non-goal**: when `parse()` detects
64
+ `bun.lockb` magic bytes it throws with a hint to migrate via bun's
65
+ own tooling (`bun install --save-text-lockfile`). The library handles
66
+ the resulting `bun.lock` via the `bun-text` adapter. bun's own
67
+ binary reader stays in bun for back-compat — that is bun's
68
+ responsibility, not ours.
69
+
70
+ ## Sources
71
+
72
+ Where each schema is canonically defined. Permalinks pinned at specific
73
+ release tags / commits so claims here stay anchored.
74
+
75
+ ### npm
76
+
77
+ - [npm v7 series — beta release & semver-major changes](https://blog.npmjs.org/post/626173315965468672/npm-v7-series-beta-release-and-semver-major.html)
78
+ — introduces `lockfileVersion: 2` (`packages` block, workspaces).
79
+ - [package-lock.json docs (npm v9)](https://docs.npmjs.com/cli/v9/configuring-npm/package-lock-json/)
80
+ — schema reference for v3.
81
+ - [GitHub: dependency-graph and Dependabot support npm v9](https://github.blog/changelog/2023-03-10-dependency-graph-and-dependabot-support-npm-v9/)
82
+ — confirms v3 drops the legacy `dependencies` mirror.
83
+
84
+ ### yarn
85
+
86
+ - [`Project.ts` at @yarnpkg/cli/2.4.3](https://github.com/yarnpkg/berry/blob/@yarnpkg/cli/2.4.3/packages/yarnpkg-core/sources/Project.ts)
87
+ — `LOCKFILE_VERSION = 4`.
88
+ - [`Project.ts` at @yarnpkg/cli/3.1.0](https://github.com/yarnpkg/berry/blob/@yarnpkg/cli/3.1.0/packages/yarnpkg-core/sources/Project.ts)
89
+ — `LOCKFILE_VERSION = 5` (one-minor window).
90
+ - [`Project.ts` at @yarnpkg/cli/3.2.0](https://github.com/yarnpkg/berry/blob/@yarnpkg/cli/3.2.0/packages/yarnpkg-core/sources/Project.ts)
91
+ — `LOCKFILE_VERSION = 6`.
92
+ - [`Project.ts` at @yarnpkg/cli/4.0.0](https://github.com/yarnpkg/berry/blob/@yarnpkg/cli/4.0.0/packages/yarnpkg-core/sources/Project.ts)
93
+ — bumps to 8; `YARN_LOCKFILE_VERSION_OVERRIDE` env var introduced here.
94
+ - [`Project.ts` at @yarnpkg/cli/4.14.1](https://github.com/yarnpkg/berry/blob/@yarnpkg/cli/4.14.1/packages/yarnpkg-core/sources/Project.ts)
95
+ — current `LOCKFILE_VERSION = 9`.
96
+ - [Yarn 4.0 release blog](https://yarnpkg.com/blog/release/4.0)
97
+ — narrative context (no explicit lockfile-bump mention).
98
+
99
+ ### pnpm
100
+
101
+ - [`pnpm/spec` — lockfile/](https://github.com/pnpm/spec/tree/master/lockfile)
102
+ — official per-version schema docs (`5.md`, `5.2.md`, `6.0.md`, `9.0.md`).
103
+ - [`pnpm/spec/lockfile/6.0.md`](https://github.com/pnpm/spec/blob/master/lockfile/6.0.md)
104
+ — pnpm 8's schema, including the package-id grammar shift.
105
+ - [`pnpm/spec/lockfile/9.0.md`](https://github.com/pnpm/spec/blob/master/lockfile/9.0.md)
106
+ — pnpm 9's `packages` / `snapshots` split.
107
+ - [pnpm Discussion #6857](https://github.com/orgs/pnpm/discussions/6857)
108
+ — maintainer rationale for the `6 → 9` jump:
109
+ *"in the future lockfile version will equal the pnpm version in
110
+ which it got introduced."*
111
+
112
+ ### bun
113
+
114
+ - [Bun docs — Lockfile](https://bun.com/docs/pm/lockfile)
115
+ — current schema reference for `bun.lock`.
116
+ - [Bun blog — text-based lockfile](https://bun.com/blog/bun-lock-text-lockfile)
117
+ — text format introduced in 1.1.39, default in 1.2.
118
+ - [`bun-lock` source](https://github.com/oven-sh/bun) — `src/install/lockfile.zig`
119
+ for the binary serializer.
120
+
@@ -0,0 +1,14 @@
1
+ import { D as Diagnostic } from './graph-DbCmOfBk.js';
2
+
3
+ interface NpmFamilyParseOptions {
4
+ }
5
+ interface NpmFamilyStringifyOptions {
6
+ lineEnding?: 'lf' | 'crlf';
7
+ onDiagnostic?: (diagnostic: Diagnostic) => void;
8
+ }
9
+ interface NpmFamilyEnrichOptions {
10
+ }
11
+ interface NpmFamilyOptimizeOptions {
12
+ }
13
+
14
+ export type { NpmFamilyEnrichOptions as N, NpmFamilyOptimizeOptions as a, NpmFamilyParseOptions as b, NpmFamilyStringifyOptions as c };
@@ -0,0 +1,37 @@
1
+ import { D as Diagnostic } from './graph-DbCmOfBk.js';
2
+
3
+ interface PnpmFamilyParseOptions {
4
+ /**
5
+ * Filesystem root used by F2 patch-slot extraction (ADR-0014 §4.F2).
6
+ * When the `overrides:` block carries `patch:<spec>#<workspace-path>`
7
+ * entries the resolver reads `<workspaceRoot>/<workspace-path>` bytes
8
+ * and emits the canonical sha512-hex on `Node.patch`. Absent / unreadable
9
+ * patch sources fall back to the ADR-0011 `unresolved-<sha256-hex>`
10
+ * sentinel computed from the locator string.
11
+ */
12
+ workspaceRoot?: string;
13
+ }
14
+ interface PnpmFamilyStringifyOptions {
15
+ lineEnding?: 'lf' | 'crlf';
16
+ settings?: PnpmSettings;
17
+ onDiagnostic?: (diagnostic: Diagnostic) => void;
18
+ }
19
+ interface PnpmManifest {
20
+ name?: string;
21
+ version?: string;
22
+ dependencies?: Record<string, string>;
23
+ devDependencies?: Record<string, string>;
24
+ optionalDependencies?: Record<string, string>;
25
+ peerDependencies?: Record<string, string>;
26
+ }
27
+ interface PnpmFamilyEnrichOptions {
28
+ manifests?: Record<string, PnpmManifest>;
29
+ }
30
+ interface PnpmFamilyOptimizeOptions {
31
+ }
32
+ interface PnpmSettings {
33
+ autoInstallPeers?: boolean;
34
+ excludeLinksFromLockfile?: boolean;
35
+ }
36
+
37
+ export type { PnpmFamilyEnrichOptions as P, PnpmManifest as a, PnpmFamilyOptimizeOptions as b, PnpmFamilyParseOptions as c, PnpmSettings as d, PnpmFamilyStringifyOptions as e };
@@ -0,0 +1,16 @@
1
+ import { D as Diagnostic } from './graph-DbCmOfBk.js';
2
+
3
+ interface YarnBerryFamilyParseOptions {
4
+ workspaceRoot?: string;
5
+ }
6
+ interface YarnBerryFamilyStringifyOptions {
7
+ lineEnding?: 'lf' | 'crlf';
8
+ cacheKey?: string;
9
+ onDiagnostic?: (diagnostic: Diagnostic) => void;
10
+ }
11
+ interface YarnBerryFamilyEnrichOptions {
12
+ }
13
+ interface YarnBerryFamilyOptimizeOptions {
14
+ }
15
+
16
+ export type { YarnBerryFamilyEnrichOptions as Y, YarnBerryFamilyOptimizeOptions as a, YarnBerryFamilyParseOptions as b, YarnBerryFamilyStringifyOptions as c };
@@ -0,0 +1,68 @@
1
+ import { N as NodeId, D as Diagnostic, G as Graph, E as EdgeTriple, a as Node, b as EdgeKind } from './graph-DbCmOfBk.js';
2
+ import { R as RegistryAdapter } from './types-Ci06KZkZ.js';
3
+
4
+ interface CompletionSeed {
5
+ /** NodeIds the modifier added in the just-completed mutate phase. */
6
+ recentlyAdded: Set<NodeId>;
7
+ /** NodeIds the mutate phase orphaned. The completion frontier excludes
8
+ * these — optimize phase collects. */
9
+ recentlyOrphaned: Set<NodeId>;
10
+ }
11
+ interface CompletionResult {
12
+ graph: Graph;
13
+ added: NodeId[];
14
+ wired: EdgeTriple[];
15
+ unresolved: Diagnostic[];
16
+ }
17
+ interface CompletionOptions {
18
+ seed?: CompletionSeed;
19
+ onDiagnostic?: (d: Diagnostic) => void;
20
+ }
21
+ /**
22
+ * Walk graph, query registry for missing transitive deps, wire edges.
23
+ * Monotone-additive: returned graph ⊇ input graph (no removals).
24
+ */
25
+ declare function completeTransitives(graph: Graph, registry: RegistryAdapter, options?: CompletionOptions): Promise<CompletionResult>;
26
+
27
+ /**
28
+ * Walk consumer → root via incoming-edge BFS.
29
+ * Returns nodes in BFS order: consumer first, deeper ancestors last.
30
+ * Cycles tolerated via `seen`.
31
+ */
32
+ declare function ancestorsOf(graph: Graph, consumer: NodeId): Node[];
33
+ /**
34
+ * Find-up resolve per ADR-0023 §5.1.
35
+ *
36
+ * Returns the closest-ancestor satisfying node, or undefined if either
37
+ * (a) no ancestor declares `name` at all → caller may install nested at the
38
+ * consumer's level, or
39
+ * (b) the closest ancestor that declares `name` does so with a conflicting
40
+ * range → "block hoist", caller installs nested fallback (npm-3 style).
41
+ *
42
+ * Tiebreaker:
43
+ * 1. Highest semver-comparable version wins (`semver.rcompare`).
44
+ * 2. On version tie, lowest NodeId lex order wins.
45
+ *
46
+ * `depKind` is part of the §5.1 normative signature but does NOT affect the
47
+ * algorithm body in v1: every dep-kind (dep / dev / optional / peer) follows
48
+ * the same closest-ancestor reuse + block-hoist contract. The parameter is
49
+ * carried verbatim so future kind-filtered hoist policies (e.g. peer-deps
50
+ * needing a stricter find-up, or optional-deps allowed to silently fail
51
+ * differently from regular deps) can branch on it without a signature
52
+ * migration. Per the ADR §5.1 pseudocode body and the v1 normative scope, no
53
+ * kind-specific branch is taken yet.
54
+ */
55
+ declare function resolveFindUp(graph: Graph, consumerId: NodeId, name: string, range: string, depKind: EdgeKind): NodeId | undefined;
56
+
57
+ type CompletionDiagnosticCode = 'COMPLETION_NODE_ADDED' | 'COMPLETION_EDGE_RESOLVED' | 'COMPLETION_UNRESOLVED' | 'COMPLETION_NODE_UNKNOWN' | 'COMPLETION_VERSION_UNKNOWN' | 'COMPLETION_PEER_CONTEXT_INCOMPLETE';
58
+ interface CompletionDiagnostic extends Diagnostic {
59
+ code: CompletionDiagnosticCode;
60
+ }
61
+ declare function completionNodeAdded(nodeId: NodeId): CompletionDiagnostic;
62
+ declare function completionEdgeResolved(triple: EdgeTriple): CompletionDiagnostic;
63
+ declare function completionUnresolved(consumer: NodeId, depName: string, depRange: string): CompletionDiagnostic;
64
+ declare function completionNodeUnknown(nodeId: NodeId): CompletionDiagnostic;
65
+ declare function completionVersionUnknown(nodeId: NodeId): CompletionDiagnostic;
66
+ declare function completionPeerContextIncomplete(nodeId: NodeId, peerName: string, peerRange: string): CompletionDiagnostic;
67
+
68
+ export { type CompletionDiagnostic, type CompletionDiagnosticCode, type CompletionOptions, type CompletionResult, type CompletionSeed, ancestorsOf, completeTransitives, completionEdgeResolved, completionNodeAdded, completionNodeUnknown, completionPeerContextIncomplete, completionUnresolved, completionVersionUnknown, resolveFindUp };