flatlock 1.3.0 → 1.5.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.
Files changed (38) hide show
  1. package/bin/flatcover.js +322 -58
  2. package/bin/flatlock-cmp.js +2 -2
  3. package/dist/compare.d.ts +85 -0
  4. package/dist/compare.d.ts.map +1 -0
  5. package/dist/detect.d.ts +33 -0
  6. package/dist/detect.d.ts.map +1 -0
  7. package/dist/index.d.ts +72 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/parsers/index.d.ts +5 -0
  10. package/dist/parsers/index.d.ts.map +1 -0
  11. package/dist/parsers/npm.d.ts +154 -0
  12. package/dist/parsers/npm.d.ts.map +1 -0
  13. package/dist/parsers/pnpm/detect.d.ts +136 -0
  14. package/dist/parsers/pnpm/detect.d.ts.map +1 -0
  15. package/dist/parsers/pnpm/index.d.ts +154 -0
  16. package/dist/parsers/pnpm/index.d.ts.map +1 -0
  17. package/dist/parsers/pnpm/internal.d.ts +5 -0
  18. package/dist/parsers/pnpm/internal.d.ts.map +1 -0
  19. package/dist/parsers/pnpm/shrinkwrap.d.ts +129 -0
  20. package/dist/parsers/pnpm/shrinkwrap.d.ts.map +1 -0
  21. package/dist/parsers/pnpm/v5.d.ts +139 -0
  22. package/dist/parsers/pnpm/v5.d.ts.map +1 -0
  23. package/dist/parsers/pnpm/v6plus.d.ts +212 -0
  24. package/dist/parsers/pnpm/v6plus.d.ts.map +1 -0
  25. package/dist/parsers/pnpm.d.ts +2 -0
  26. package/dist/parsers/pnpm.d.ts.map +1 -0
  27. package/dist/parsers/types.d.ts +23 -0
  28. package/dist/parsers/types.d.ts.map +1 -0
  29. package/dist/parsers/yarn-berry.d.ts +197 -0
  30. package/dist/parsers/yarn-berry.d.ts.map +1 -0
  31. package/dist/parsers/yarn-classic.d.ts +110 -0
  32. package/dist/parsers/yarn-classic.d.ts.map +1 -0
  33. package/dist/result.d.ts +12 -0
  34. package/dist/result.d.ts.map +1 -0
  35. package/dist/set.d.ts +238 -0
  36. package/dist/set.d.ts.map +1 -0
  37. package/package.json +9 -4
  38. package/src/compare.js +5 -7
@@ -0,0 +1,197 @@
1
+ /** @typedef {import('./types.js').Dependency} Dependency */
2
+ /**
3
+ * @typedef {Object} WorkspacePackage
4
+ * @property {string} name
5
+ * @property {string} version
6
+ * @property {Record<string, string>} [dependencies]
7
+ * @property {Record<string, string>} [devDependencies]
8
+ * @property {Record<string, string>} [optionalDependencies]
9
+ * @property {Record<string, string>} [peerDependencies]
10
+ */
11
+ /**
12
+ * Extract package name from yarn berry resolution field.
13
+ *
14
+ * The resolution field is the CANONICAL identifier and should be used instead of the key.
15
+ * Keys can contain npm aliases (e.g., "string-width-cjs@npm:string-width@^4.2.0") while
16
+ * the resolution always contains the actual package name (e.g., "string-width@npm:4.2.3").
17
+ *
18
+ * @param {string} resolution - Resolution field from lockfile entry
19
+ * @returns {string | null} Package name or null if parsing fails
20
+ *
21
+ * @example
22
+ * // Unscoped npm package
23
+ * parseResolution('lodash@npm:4.17.21')
24
+ * // => 'lodash'
25
+ *
26
+ * @example
27
+ * // Scoped npm package
28
+ * parseResolution('@babel/core@npm:7.24.0')
29
+ * // => '@babel/core'
30
+ *
31
+ * @example
32
+ * // Aliased package - resolution shows the REAL package name
33
+ * // (key was "string-width-cjs@npm:string-width@^4.2.0")
34
+ * parseResolution('string-width@npm:4.2.3')
35
+ * // => 'string-width'
36
+ *
37
+ * @example
38
+ * // Scoped aliased package - resolution shows the REAL package name
39
+ * // (key was "@babel-baseline/core@npm:@babel/core@7.24.4")
40
+ * parseResolution('@babel/core@npm:7.24.4')
41
+ * // => '@babel/core'
42
+ *
43
+ * @example
44
+ * // Patch protocol (nested protocols)
45
+ * parseResolution('pkg@patch:pkg@npm:1.0.0#./patch')
46
+ * // => 'pkg'
47
+ *
48
+ * @example
49
+ * // Scoped package with patch protocol
50
+ * parseResolution('@scope/pkg@patch:@scope/pkg@npm:1.0.0#./fix.patch')
51
+ * // => '@scope/pkg'
52
+ *
53
+ * @example
54
+ * // Workspace protocol
55
+ * parseResolution('my-pkg@workspace:packages/my-pkg')
56
+ * // => 'my-pkg'
57
+ *
58
+ * @example
59
+ * // Scoped workspace package
60
+ * parseResolution('@myorg/utils@workspace:packages/utils')
61
+ * // => '@myorg/utils'
62
+ *
63
+ * @example
64
+ * // Git protocol
65
+ * parseResolution('my-lib@git:github.com/user/repo#commit-hash')
66
+ * // => 'my-lib'
67
+ *
68
+ * @example
69
+ * // Null/empty input
70
+ * parseResolution(null)
71
+ * // => null
72
+ *
73
+ * @example
74
+ * // Empty string
75
+ * parseResolution('')
76
+ * // => null
77
+ *
78
+ * @example
79
+ * // Portal protocol (symlink to external package)
80
+ * parseResolution('@scope/external@portal:../external-pkg')
81
+ * // => '@scope/external'
82
+ */
83
+ export function parseResolution(resolution: string): string | null;
84
+ /**
85
+ * Extract package name from yarn berry key (fallback for when resolution is unavailable).
86
+ *
87
+ * WARNING: Keys can contain npm aliases. Prefer parseResolution() when possible.
88
+ * The key may return an alias name instead of the real package name.
89
+ *
90
+ * @param {string} key - Lockfile entry key
91
+ * @returns {string} Package name (may be alias name, not canonical name)
92
+ *
93
+ * @example
94
+ * // Simple unscoped package
95
+ * parseLockfileKey('lodash@npm:^4.17.21')
96
+ * // => 'lodash'
97
+ *
98
+ * @example
99
+ * // Scoped package
100
+ * parseLockfileKey('@babel/core@npm:^7.24.0')
101
+ * // => '@babel/core'
102
+ *
103
+ * @example
104
+ * // Multiple version ranges (comma-separated) - takes first entry
105
+ * parseLockfileKey('@types/node@npm:^18.0.0, @types/node@npm:^20.0.0')
106
+ * // => '@types/node'
107
+ *
108
+ * @example
109
+ * // npm alias - returns the ALIAS name (not real package)
110
+ * // Use parseResolution() for the real package name
111
+ * parseLockfileKey('string-width-cjs@npm:string-width@^4.2.0')
112
+ * // => 'string-width-cjs'
113
+ *
114
+ * @example
115
+ * // Scoped npm alias
116
+ * parseLockfileKey('@babel-baseline/core@npm:@babel/core@7.24.4')
117
+ * // => '@babel-baseline/core'
118
+ *
119
+ * @example
120
+ * // Workspace protocol
121
+ * parseLockfileKey('my-pkg@workspace:packages/my-pkg')
122
+ * // => 'my-pkg'
123
+ *
124
+ * @example
125
+ * // Scoped workspace package
126
+ * parseLockfileKey('@myorg/utils@workspace:.')
127
+ * // => '@myorg/utils'
128
+ *
129
+ * @example
130
+ * // Portal protocol
131
+ * parseLockfileKey('external-pkg@portal:../some/path')
132
+ * // => 'external-pkg'
133
+ *
134
+ * @example
135
+ * // Link protocol
136
+ * parseLockfileKey('linked-pkg@link:./local')
137
+ * // => 'linked-pkg'
138
+ *
139
+ * @example
140
+ * // Patch protocol (complex nested format)
141
+ * parseLockfileKey('pkg@patch:pkg@npm:1.0.0#./patches/fix.patch')
142
+ * // => 'pkg'
143
+ *
144
+ * @example
145
+ * // Scoped patch
146
+ * parseLockfileKey('@scope/pkg@patch:@scope/pkg@npm:1.0.0#./fix.patch')
147
+ * // => '@scope/pkg'
148
+ *
149
+ * @example
150
+ * // File protocol
151
+ * parseLockfileKey('local-pkg@file:../local-package')
152
+ * // => 'local-pkg'
153
+ */
154
+ export function parseLockfileKey(key: string): string;
155
+ /**
156
+ * Parse yarn.lock v2+ (berry)
157
+ * @param {string | object} input - Lockfile content string or pre-parsed object
158
+ * @param {Object} [_options] - Parser options (unused, reserved for future use)
159
+ * @returns {Generator<Dependency>}
160
+ */
161
+ export function fromYarnBerryLock(input: string | object, _options?: Object): Generator<Dependency>;
162
+ /**
163
+ * Extract workspace paths from yarn berry lockfile.
164
+ *
165
+ * Yarn berry workspace entries use `@workspace:` protocol in keys.
166
+ * Keys can have multiple comma-separated descriptors.
167
+ *
168
+ * @param {string | object} input - Lockfile content string or pre-parsed object
169
+ * @returns {string[]} Array of workspace paths (e.g., ['packages/foo', 'packages/bar'])
170
+ *
171
+ * @example
172
+ * extractWorkspacePaths(lockfile)
173
+ * // => ['packages/babel-core', 'packages/babel-parser', ...]
174
+ */
175
+ export function extractWorkspacePaths(input: string | object): string[];
176
+ /**
177
+ * Build workspace packages map by reading package.json files.
178
+ *
179
+ * @param {string | object} input - Lockfile content string or pre-parsed object
180
+ * @param {string} repoDir - Path to repository root
181
+ * @returns {Promise<Record<string, WorkspacePackage>>} Map of workspace path to package info
182
+ *
183
+ * @example
184
+ * const workspaces = await buildWorkspacePackages(lockfile, '/path/to/repo');
185
+ * // => { 'packages/foo': { name: '@scope/foo', version: '1.0.0', dependencies: {...} } }
186
+ */
187
+ export function buildWorkspacePackages(input: string | object, repoDir: string): Promise<Record<string, WorkspacePackage>>;
188
+ export type Dependency = import("./types.js").Dependency;
189
+ export type WorkspacePackage = {
190
+ name: string;
191
+ version: string;
192
+ dependencies?: Record<string, string>;
193
+ devDependencies?: Record<string, string>;
194
+ optionalDependencies?: Record<string, string>;
195
+ peerDependencies?: Record<string, string>;
196
+ };
197
+ //# sourceMappingURL=yarn-berry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yarn-berry.d.ts","sourceRoot":"","sources":["../../src/parsers/yarn-berry.js"],"names":[],"mappings":"AAIA,4DAA4D;AAE5D;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,4CAjEW,MAAM,GACJ,MAAM,GAAG,IAAI,CA4FzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqEG;AACH,sCAhEW,MAAM,GACJ,MAAM,CAiGlB;AAED;;;;;GAKG;AACH,yCAJW,MAAM,GAAG,MAAM,aACf,MAAM,GACJ,SAAS,CAAC,UAAU,CAAC,CAqCjC;AAED;;;;;;;;;;;;GAYG;AACH,6CAPW,MAAM,GAAG,MAAM,GACb,MAAM,EAAE,CA+BpB;AAED;;;;;;;;;;GAUG;AACH,8CARW,MAAM,GAAG,MAAM,WACf,MAAM,GACJ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CA6BrD;yBAjVa,OAAO,YAAY,EAAE,UAAU;;UAI/B,MAAM;aACN,MAAM;mBACN,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;sBACtB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;2BACtB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;uBACtB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3
+ * !! WARNING: DO NOT MODIFY THIS FUNCTION !!
4
+ * !! AI AGENTS (Claude, Copilot, etc.): DO NOT TOUCH THIS CODE !!
5
+ * !! !!
6
+ * !! This is YARN LOCKFILE KEY parsing, NOT npm spec parsing. !!
7
+ * !! Yarn lockfile keys have their own format: !!
8
+ * !! - Multiple comma-separated entries: "pkg@^1.0.0, pkg@^2.0.0" !!
9
+ * !! - npm: aliasing protocol: "alias@npm:actual@^1.0.0" !!
10
+ * !! !!
11
+ * !! npm-package-arg (npa) does NOT understand these formats. !!
12
+ * !! Do not "improve" this with npa. !!
13
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
14
+ *
15
+ * Extract package name from yarn classic key.
16
+ *
17
+ * @param {string} key - Lockfile entry key
18
+ * @returns {string} Package name
19
+ *
20
+ * @example
21
+ * // Simple unscoped package with semver range
22
+ * parseLockfileKey('lodash@^4.17.21')
23
+ * // => 'lodash'
24
+ *
25
+ * @example
26
+ * // Scoped package
27
+ * parseLockfileKey('@babel/core@^7.0.0')
28
+ * // => '@babel/core'
29
+ *
30
+ * @example
31
+ * // Multiple version ranges (comma-separated) - takes first entry
32
+ * parseLockfileKey('lodash@^4.17.21, lodash@^4.0.0')
33
+ * // => 'lodash'
34
+ *
35
+ * @example
36
+ * // Multiple ranges for scoped package
37
+ * parseLockfileKey('@types/node@^18.0.0, @types/node@^20.0.0')
38
+ * // => '@types/node'
39
+ *
40
+ * @example
41
+ * // npm: alias protocol - returns the ALIAS name
42
+ * parseLockfileKey('@babel/traverse--for-generate-function-map@npm:@babel/traverse@^7.25.3')
43
+ * // => '@babel/traverse--for-generate-function-map'
44
+ *
45
+ * @example
46
+ * // Unscoped alias
47
+ * parseLockfileKey('string-width-cjs@npm:string-width@^4.2.0')
48
+ * // => 'string-width-cjs'
49
+ *
50
+ * @example
51
+ * // Exact version
52
+ * parseLockfileKey('typescript@5.3.3')
53
+ * // => 'typescript'
54
+ *
55
+ * @example
56
+ * // Git URL specifier
57
+ * parseLockfileKey('my-lib@github:user/repo#v1.0.0')
58
+ * // => 'my-lib'
59
+ *
60
+ * @example
61
+ * // Tarball URL
62
+ * parseLockfileKey('custom-pkg@https://example.com/pkg.tgz')
63
+ * // => 'custom-pkg'
64
+ *
65
+ * @example
66
+ * // Package with prerelease version
67
+ * parseLockfileKey('@next/env@^14.0.0-canary.0')
68
+ * // => '@next/env'
69
+ *
70
+ * @example
71
+ * // Package without @ (bare name, edge case)
72
+ * parseLockfileKey('lodash')
73
+ * // => 'lodash'
74
+ *
75
+ * @example
76
+ * // Deeply scoped alias pointing to scoped package
77
+ * parseLockfileKey('@myorg/my-alias@npm:@original/package@^1.0.0')
78
+ * // => '@myorg/my-alias'
79
+ */
80
+ export function parseLockfileKey(key: string): string;
81
+ /**
82
+ * Parse yarn.lock v1 (classic)
83
+ * @param {string | object} input - Lockfile content string or pre-parsed object
84
+ * @param {Object} [_options] - Parser options (unused, reserved for future use)
85
+ * @returns {Generator<Dependency>}
86
+ */
87
+ export function fromYarnClassicLock(input: string | object, _options?: Object): Generator<Dependency>;
88
+ /** @typedef {import('./types.js').Dependency} Dependency */
89
+ /**
90
+ * @typedef {Object} YarnClassicParseResult
91
+ * @property {'success' | 'merge' | 'conflict'} type - Parse result type
92
+ * @property {Record<string, any>} object - Parsed lockfile object
93
+ */
94
+ /**
95
+ * The yarn classic parse function (handles CJS/ESM interop)
96
+ * @type {(content: string) => YarnClassicParseResult}
97
+ */
98
+ export const parseYarnClassic: (content: string) => YarnClassicParseResult;
99
+ export type Dependency = import("./types.js").Dependency;
100
+ export type YarnClassicParseResult = {
101
+ /**
102
+ * - Parse result type
103
+ */
104
+ type: "success" | "merge" | "conflict";
105
+ /**
106
+ * - Parsed lockfile object
107
+ */
108
+ object: Record<string, any>;
109
+ };
110
+ //# sourceMappingURL=yarn-classic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yarn-classic.d.ts","sourceRoot":"","sources":["../../src/parsers/yarn-classic.js"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8EG;AACH,sCA/DW,MAAM,GACJ,MAAM,CA8FlB;AAED;;;;;GAKG;AACH,2CAJW,MAAM,GAAG,MAAM,aACf,MAAM,GACJ,SAAS,CAAC,UAAU,CAAC,CAgCjC;AAnKD,4DAA4D;AAE5D;;;;GAIG;AAEH;;;GAGG;AACH,+BAFU,CAAC,OAAO,EAAE,MAAM,KAAK,sBAAsB,CAE6B;yBAZpE,OAAO,YAAY,EAAE,UAAU;;;;;UAI/B,SAAS,GAAG,OAAO,GAAG,UAAU;;;;YAChC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC"}
@@ -0,0 +1,12 @@
1
+ export function Ok<T>(value: T): OkResult<T>;
2
+ export function Err(error: Error | string): ErrResult;
3
+ export type OkResult<T> = {
4
+ ok: true;
5
+ value: T;
6
+ };
7
+ export type ErrResult = {
8
+ ok: false;
9
+ error: Error;
10
+ };
11
+ export type Result<T> = OkResult<T> | ErrResult;
12
+ //# sourceMappingURL=result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../src/result.js"],"names":[],"mappings":"AAwBO,mBAJM,CAAC,SACH,CAAC,GACC,QAAQ,CAAC,CAAC,CAAC,CAEwB;AAOzC,2BAHI,KAAK,GAAG,MAAM,GACZ,SAAS,CAKpB;qBAjCW,CAAC;QAEA,IAAI;WACJ,CAAC;;;QAKD,KAAK;WACL,KAAK;;mBAIN,CAAC,IACD,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS"}
package/dist/set.d.ts ADDED
@@ -0,0 +1,238 @@
1
+ /**
2
+ * A Set-like container for lockfile dependencies.
3
+ *
4
+ * Identity is determined by name@version. Two dependencies with the same
5
+ * name and version are considered equal, regardless of integrity or resolved URL.
6
+ *
7
+ * All set operations return new FlatlockSet instances (immutable pattern).
8
+ *
9
+ * NOTE: Set operations (union, intersection, difference) return sets that
10
+ * cannot use dependenciesOf() because they lack lockfile traversal data.
11
+ *
12
+ * @example
13
+ * const set = await FlatlockSet.fromPath('./package-lock.json');
14
+ * console.log(set.size); // 1234
15
+ * console.log(set.has('lodash@4.17.21')); // true
16
+ *
17
+ * // Get dependencies for a specific workspace
18
+ * const pkg = JSON.parse(await readFile('./packages/foo/package.json'));
19
+ * const subset = await set.dependenciesOf(pkg, { workspacePath: 'packages/foo', repoDir: '.' });
20
+ *
21
+ * // Set operations
22
+ * const other = await FlatlockSet.fromPath('./other-lock.json');
23
+ * const common = set.intersection(other);
24
+ */
25
+ export class FlatlockSet {
26
+ /**
27
+ * Create FlatlockSet from lockfile path (auto-detect type)
28
+ * @param {string} path - Path to lockfile
29
+ * @param {FromStringOptions} [options] - Parser options
30
+ * @returns {Promise<FlatlockSet>}
31
+ */
32
+ static fromPath(path: string, options?: FromStringOptions): Promise<FlatlockSet>;
33
+ /**
34
+ * Create FlatlockSet from lockfile string
35
+ * @param {string} content - Lockfile content
36
+ * @param {FromStringOptions} [options] - Parser options
37
+ * @returns {FlatlockSet}
38
+ */
39
+ static fromString(content: string, options?: FromStringOptions): FlatlockSet;
40
+ /**
41
+ * Parse lockfile once, returning both processed deps and raw data
42
+ * @param {string} content
43
+ * @param {LockfileType} type
44
+ * @param {FromStringOptions} options
45
+ * @returns {{ deps: Map<string, Dependency>, packages: LockfilePackages, importers: LockfileImporters | null, snapshots: Record<string, any> | null }}
46
+ */
47
+ static "__#private@#parseAll"(content: string, type: LockfileType, options: FromStringOptions): {
48
+ deps: Map<string, Dependency>;
49
+ packages: LockfilePackages;
50
+ importers: LockfileImporters | null;
51
+ snapshots: Record<string, any> | null;
52
+ };
53
+ /**
54
+ * @param {symbol} internal - Must be INTERNAL symbol
55
+ * @param {Map<string, Dependency>} deps
56
+ * @param {LockfilePackages | null} packages
57
+ * @param {LockfileImporters | null} importers
58
+ * @param {Record<string, any> | null} snapshots
59
+ * @param {LockfileType | null} type
60
+ */
61
+ constructor(internal: symbol, deps: Map<string, Dependency>, packages: LockfilePackages | null, importers: LockfileImporters | null, snapshots: Record<string, any> | null, type: LockfileType | null);
62
+ /** @returns {number} */
63
+ get size(): number;
64
+ /** @returns {LockfileType | null} */
65
+ get type(): LockfileType | null;
66
+ /** @returns {boolean} */
67
+ get canTraverse(): boolean;
68
+ /**
69
+ * Get workspace paths from lockfile.
70
+ * Supports npm, pnpm, and yarn berry lockfiles.
71
+ * @returns {string[]} Array of workspace paths (e.g., ['packages/foo', 'packages/bar'])
72
+ */
73
+ getWorkspacePaths(): string[];
74
+ /**
75
+ * Check if a dependency exists
76
+ * @param {string} nameAtVersion - e.g., "lodash@4.17.21"
77
+ * @returns {boolean}
78
+ */
79
+ has(nameAtVersion: string): boolean;
80
+ /**
81
+ * Get a dependency by name@version
82
+ * @param {string} nameAtVersion
83
+ * @returns {Dependency | undefined}
84
+ */
85
+ get(nameAtVersion: string): Dependency | undefined;
86
+ /** @returns {IterableIterator<Dependency>} */
87
+ values(): IterableIterator<Dependency>;
88
+ /** @returns {IterableIterator<string>} */
89
+ keys(): IterableIterator<string>;
90
+ /** @returns {IterableIterator<[string, Dependency]>} */
91
+ entries(): IterableIterator<[string, Dependency]>;
92
+ /**
93
+ * Execute a callback for each dependency
94
+ * @param {(dep: Dependency, key: string, set: FlatlockSet) => void} callback
95
+ * @param {any} [thisArg]
96
+ */
97
+ forEach(callback: (dep: Dependency, key: string, set: FlatlockSet) => void, thisArg?: any): void;
98
+ /**
99
+ * Union of this set with another
100
+ * @param {FlatlockSet} other
101
+ * @returns {FlatlockSet}
102
+ */
103
+ union(other: FlatlockSet): FlatlockSet;
104
+ /**
105
+ * Intersection of this set with another
106
+ * @param {FlatlockSet} other
107
+ * @returns {FlatlockSet}
108
+ */
109
+ intersection(other: FlatlockSet): FlatlockSet;
110
+ /**
111
+ * Difference: elements in this set but not in other
112
+ * @param {FlatlockSet} other
113
+ * @returns {FlatlockSet}
114
+ */
115
+ difference(other: FlatlockSet): FlatlockSet;
116
+ /**
117
+ * Check if this set is a subset of another
118
+ * @param {FlatlockSet} other
119
+ * @returns {boolean}
120
+ */
121
+ isSubsetOf(other: FlatlockSet): boolean;
122
+ /**
123
+ * Check if this set is a superset of another
124
+ * @param {FlatlockSet} other
125
+ * @returns {boolean}
126
+ */
127
+ isSupersetOf(other: FlatlockSet): boolean;
128
+ /**
129
+ * Check if this set has no elements in common with another
130
+ * @param {FlatlockSet} other
131
+ * @returns {boolean}
132
+ */
133
+ isDisjointFrom(other: FlatlockSet): boolean;
134
+ /**
135
+ * Get transitive dependencies of a package.json
136
+ *
137
+ * For monorepos, provide workspacePath and repoDir to get correct resolution.
138
+ * Without workspacePath, assumes root package (hoisted deps only).
139
+ *
140
+ * NOTE: This method is only available on sets created directly from
141
+ * fromPath/fromString. Sets created via union/intersection/difference
142
+ * cannot use this method (canTraverse will be false).
143
+ *
144
+ * @param {PackageJson} packageJson - Parsed package.json
145
+ * @param {DependenciesOfOptions} [options]
146
+ * @returns {Promise<FlatlockSet>}
147
+ * @throws {Error} If called on a set that cannot traverse
148
+ *
149
+ * @example
150
+ * // Simple usage with repoDir (recommended)
151
+ * const deps = await lockfile.dependenciesOf(pkg, {
152
+ * workspacePath: 'packages/foo',
153
+ * repoDir: '/path/to/repo'
154
+ * });
155
+ */
156
+ dependenciesOf(packageJson: PackageJson, options?: DependenciesOfOptions): Promise<FlatlockSet>;
157
+ /**
158
+ * Convert to array
159
+ * @returns {Dependency[]}
160
+ */
161
+ toArray(): Dependency[];
162
+ /** @returns {IterableIterator<Dependency>} */
163
+ [Symbol.iterator](): IterableIterator<Dependency>;
164
+ #private;
165
+ }
166
+ export type Dependency = import("./parsers/npm.js").Dependency;
167
+ export type LockfileType = import("./detect.js").LockfileType;
168
+ export type WorkspacePackage = {
169
+ /**
170
+ * - Package name (e.g., '@vue/shared')
171
+ */
172
+ name: string;
173
+ /**
174
+ * - Package version (e.g., '3.5.26')
175
+ */
176
+ version: string;
177
+ /**
178
+ * - Production dependencies (for yarn berry workspace traversal)
179
+ */
180
+ dependencies?: Record<string, string>;
181
+ /**
182
+ * - Dev dependencies
183
+ */
184
+ devDependencies?: Record<string, string>;
185
+ /**
186
+ * - Optional dependencies
187
+ */
188
+ optionalDependencies?: Record<string, string>;
189
+ /**
190
+ * - Peer dependencies
191
+ */
192
+ peerDependencies?: Record<string, string>;
193
+ };
194
+ export type DependenciesOfOptions = {
195
+ /**
196
+ * - Path to workspace (e.g., 'packages/foo')
197
+ */
198
+ workspacePath?: string;
199
+ /**
200
+ * - Path to repository root for reading workspace package.json files
201
+ */
202
+ repoDir?: string;
203
+ /**
204
+ * - Include devDependencies
205
+ */
206
+ dev?: boolean;
207
+ /**
208
+ * - Include optionalDependencies
209
+ */
210
+ optional?: boolean;
211
+ /**
212
+ * - Include peerDependencies (default false: peers are provided by consumer)
213
+ */
214
+ peer?: boolean;
215
+ /**
216
+ * - Map of workspace path to package info for resolving workspace links (auto-built if repoDir provided)
217
+ */
218
+ workspacePackages?: Record<string, WorkspacePackage>;
219
+ };
220
+ export type FromStringOptions = {
221
+ /**
222
+ * - Path hint for type detection
223
+ */
224
+ path?: string;
225
+ /**
226
+ * - Explicit lockfile type
227
+ */
228
+ type?: LockfileType;
229
+ };
230
+ export type PackageJson = {
231
+ dependencies?: Record<string, string>;
232
+ devDependencies?: Record<string, string>;
233
+ optionalDependencies?: Record<string, string>;
234
+ peerDependencies?: Record<string, string>;
235
+ };
236
+ export type LockfilePackages = Record<string, any>;
237
+ export type LockfileImporters = Record<string, any>;
238
+ //# sourceMappingURL=set.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../src/set.js"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flatlock",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "The Matlock of lockfile parsers - extracts packages without building dependency graphs",
5
5
  "keywords": [
6
6
  "lockfile",
@@ -35,9 +35,9 @@
35
35
  },
36
36
  "main": "src/index.js",
37
37
  "bin": {
38
- "flatlock": "./bin/flatlock.js",
39
- "flatlock-cmp": "./bin/flatlock-cmp.js",
40
- "flatcover": "./bin/flatcover.js"
38
+ "flatlock": "bin/flatlock.js",
39
+ "flatlock-cmp": "bin/flatlock-cmp.js",
40
+ "flatcover": "bin/flatcover.js"
41
41
  },
42
42
  "files": [
43
43
  "src",
@@ -87,6 +87,11 @@
87
87
  "@yarnpkg/core": "^4.5.0"
88
88
  },
89
89
  "packageManager": "pnpm@10.25.0",
90
+ "pnpm": {
91
+ "overrides": {
92
+ "tar": ">=7.5.3"
93
+ }
94
+ },
90
95
  "engines": {
91
96
  "node": ">=22"
92
97
  },
package/src/compare.js CHANGED
@@ -6,7 +6,7 @@ import { tmpdir } from 'node:os';
6
6
  import { dirname, join } from 'node:path';
7
7
  import { parseSyml } from '@yarnpkg/parsers';
8
8
  import yaml from 'js-yaml';
9
- import { detectType, fromPath, Type } from './index.js';
9
+ import { collect, detectType, Type } from './index.js';
10
10
  import { parseYarnBerryKey, parseYarnClassic, parseYarnClassicKey } from './parsers/index.js';
11
11
  import { parseSpec as parsePnpmSpec } from './parsers/pnpm.js';
12
12
 
@@ -545,12 +545,10 @@ export async function compare(filepath, options = {}) {
545
545
  const content = await readFile(filepath, 'utf8');
546
546
  const type = detectType({ path: filepath, content });
547
547
 
548
- const flatlockSet = new Set();
549
- for await (const dep of fromPath(filepath)) {
550
- if (dep.name && dep.version) {
551
- flatlockSet.add(`${dep.name}@${dep.version}`);
552
- }
553
- }
548
+ console.time(`⏱ collect [...]${filepath.slice(-40)}`);
549
+ const deps = await collect(filepath);
550
+ console.timeEnd(`⏱ collect [...]${filepath.slice(-40)}`);
551
+ const flatlockSet = new Set(deps.map(({ name, version }) => `${name}@${version}`));
554
552
 
555
553
  let comparisonResult;
556
554
  switch (type) {