flatlock 1.1.0 → 1.2.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.
- package/README.md +54 -1
- package/bin/flatlock-cmp.js +71 -45
- package/dist/compare.d.ts +25 -3
- package/dist/compare.d.ts.map +1 -1
- package/dist/detect.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/parsers/index.d.ts +2 -2
- package/dist/parsers/npm.d.ts +64 -37
- package/dist/parsers/npm.d.ts.map +1 -1
- package/dist/parsers/pnpm/detect.d.ts +136 -0
- package/dist/parsers/pnpm/detect.d.ts.map +1 -0
- package/dist/parsers/pnpm/index.d.ts +120 -0
- package/dist/parsers/pnpm/index.d.ts.map +1 -0
- package/dist/parsers/pnpm/internal.d.ts +5 -0
- package/dist/parsers/pnpm/internal.d.ts.map +1 -0
- package/dist/parsers/pnpm/shrinkwrap.d.ts +129 -0
- package/dist/parsers/pnpm/shrinkwrap.d.ts.map +1 -0
- package/dist/parsers/pnpm/v5.d.ts +139 -0
- package/dist/parsers/pnpm/v5.d.ts.map +1 -0
- package/dist/parsers/pnpm/v6plus.d.ts +212 -0
- package/dist/parsers/pnpm/v6plus.d.ts.map +1 -0
- package/dist/parsers/pnpm.d.ts +1 -59
- package/dist/parsers/pnpm.d.ts.map +1 -1
- package/dist/parsers/types.d.ts +23 -0
- package/dist/parsers/types.d.ts.map +1 -0
- package/dist/parsers/yarn-berry.d.ts +141 -52
- package/dist/parsers/yarn-berry.d.ts.map +1 -1
- package/dist/parsers/yarn-classic.d.ts +79 -33
- package/dist/parsers/yarn-classic.d.ts.map +1 -1
- package/dist/set.d.ts +189 -0
- package/dist/set.d.ts.map +1 -0
- package/package.json +7 -5
- package/src/compare.js +385 -28
- package/src/detect.js +3 -4
- package/src/index.js +9 -2
- package/src/parsers/index.js +10 -2
- package/src/parsers/npm.js +64 -16
- package/src/parsers/pnpm/detect.js +198 -0
- package/src/parsers/pnpm/index.js +289 -0
- package/src/parsers/pnpm/internal.js +41 -0
- package/src/parsers/pnpm/shrinkwrap.js +241 -0
- package/src/parsers/pnpm/v5.js +225 -0
- package/src/parsers/pnpm/v6plus.js +290 -0
- package/src/parsers/pnpm.js +11 -89
- package/src/parsers/types.js +10 -0
- package/src/parsers/yarn-berry.js +183 -36
- package/src/parsers/yarn-classic.js +81 -21
- package/src/set.js +618 -0
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Most lockfile parsers (like `@npmcli/arborist` or `snyk-nodejs-lockfile-parser`)
|
|
|
11
11
|
**flatlock** takes a different approach: it extracts a flat stream of packages from any lockfile format. No trees, no graphs, no edges - just packages.
|
|
12
12
|
|
|
13
13
|
```javascript
|
|
14
|
-
import * as
|
|
14
|
+
import * as flatlock from 'flatlock';
|
|
15
15
|
|
|
16
16
|
// Stream packages from any lockfile
|
|
17
17
|
for await (const pkg of flatlock.fromPath('./package-lock.json')) {
|
|
@@ -89,6 +89,59 @@ Each yielded package has:
|
|
|
89
89
|
}
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
+
## FlatlockSet
|
|
93
|
+
|
|
94
|
+
For more advanced use cases, `FlatlockSet` provides Set-like operations on lockfile dependencies:
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
import { FlatlockSet } from 'flatlock';
|
|
98
|
+
|
|
99
|
+
// Create from lockfile
|
|
100
|
+
const set = await FlatlockSet.fromPath('./package-lock.json');
|
|
101
|
+
console.log(set.size); // 1234
|
|
102
|
+
console.log(set.has('lodash@4.17.21')); // true
|
|
103
|
+
|
|
104
|
+
// Set operations (immutable - return new sets)
|
|
105
|
+
const other = await FlatlockSet.fromPath('./other-lock.json');
|
|
106
|
+
const common = set.intersection(other); // packages in both
|
|
107
|
+
const added = other.difference(set); // packages only in other
|
|
108
|
+
const all = set.union(other); // packages in either
|
|
109
|
+
|
|
110
|
+
// Predicates
|
|
111
|
+
set.isSubsetOf(other); // true if all packages in set are in other
|
|
112
|
+
set.isSupersetOf(other); // true if set contains all packages in other
|
|
113
|
+
set.isDisjointFrom(other); // true if no packages in common
|
|
114
|
+
|
|
115
|
+
// Iterate like a Set
|
|
116
|
+
for (const dep of set) {
|
|
117
|
+
console.log(dep.name, dep.version);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Workspace-Specific SBOMs
|
|
122
|
+
|
|
123
|
+
For monorepos, use `dependenciesOf()` to get only the dependencies of a specific workspace:
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
import { readFile } from 'node:fs/promises';
|
|
127
|
+
import { FlatlockSet } from 'flatlock';
|
|
128
|
+
|
|
129
|
+
const lockfile = await FlatlockSet.fromPath('./package-lock.json');
|
|
130
|
+
const pkg = JSON.parse(await readFile('./packages/api/package.json', 'utf8'));
|
|
131
|
+
|
|
132
|
+
// Get only dependencies reachable from this workspace
|
|
133
|
+
const subset = lockfile.dependenciesOf(pkg, {
|
|
134
|
+
workspacePath: 'packages/api', // for correct resolution in monorepos
|
|
135
|
+
dev: false, // exclude devDependencies
|
|
136
|
+
optional: true, // include optionalDependencies
|
|
137
|
+
peer: false // exclude peerDependencies
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
console.log(`${pkg.name} has ${subset.size} production dependencies`);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Note:** Sets created via `union()`, `intersection()`, or `difference()` cannot use `dependenciesOf()` because they lack the raw lockfile data needed for traversal. Check `set.canTraverse` before calling.
|
|
144
|
+
|
|
92
145
|
## License
|
|
93
146
|
|
|
94
147
|
Apache-2.0
|
package/bin/flatlock-cmp.js
CHANGED
|
@@ -5,18 +5,6 @@ import { join } from 'node:path';
|
|
|
5
5
|
import { parseArgs } from 'node:util';
|
|
6
6
|
import * as flatlock from '../src/index.js';
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* Get comparison parser name for type
|
|
10
|
-
*/
|
|
11
|
-
function getComparisonName(type) {
|
|
12
|
-
switch (type) {
|
|
13
|
-
case 'npm': return '@npmcli/arborist';
|
|
14
|
-
case 'yarn-classic': return '@yarnpkg/lockfile';
|
|
15
|
-
case 'yarn-berry': return '@yarnpkg/parsers';
|
|
16
|
-
case 'pnpm': return 'js-yaml';
|
|
17
|
-
default: return 'unknown';
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
8
|
|
|
21
9
|
/**
|
|
22
10
|
* Convert glob pattern to regex
|
|
@@ -59,18 +47,17 @@ async function processFile(filepath, baseDir) {
|
|
|
59
47
|
try {
|
|
60
48
|
const result = await flatlock.compare(filepath);
|
|
61
49
|
const rel = baseDir ? filepath.replace(baseDir + '/', '') : filepath;
|
|
62
|
-
const comparisonName = getComparisonName(result.type);
|
|
63
50
|
|
|
64
|
-
if (result.
|
|
51
|
+
if (result.equinumerous === null) {
|
|
65
52
|
// Unsupported type or no comparison available
|
|
66
53
|
return {
|
|
67
54
|
type: result.type,
|
|
68
55
|
path: rel,
|
|
69
|
-
|
|
56
|
+
source: result.source || 'unknown',
|
|
70
57
|
flatlockCount: result.flatlockCount,
|
|
71
58
|
comparisonCount: null,
|
|
72
59
|
workspaceCount: 0,
|
|
73
|
-
|
|
60
|
+
equinumerous: null,
|
|
74
61
|
onlyInFlatlock: null,
|
|
75
62
|
onlyInComparison: null
|
|
76
63
|
};
|
|
@@ -79,11 +66,11 @@ async function processFile(filepath, baseDir) {
|
|
|
79
66
|
return {
|
|
80
67
|
type: result.type,
|
|
81
68
|
path: rel,
|
|
82
|
-
|
|
69
|
+
source: result.source,
|
|
83
70
|
flatlockCount: result.flatlockCount,
|
|
84
71
|
comparisonCount: result.comparisonCount,
|
|
85
72
|
workspaceCount: result.workspaceCount,
|
|
86
|
-
|
|
73
|
+
equinumerous: result.equinumerous,
|
|
87
74
|
onlyInFlatlock: result.onlyInFlatlock,
|
|
88
75
|
onlyInComparison: result.onlyInComparison
|
|
89
76
|
};
|
|
@@ -118,10 +105,21 @@ Options:
|
|
|
118
105
|
-h, --help Show this help
|
|
119
106
|
|
|
120
107
|
Comparison parsers (workspace/link entries excluded from all):
|
|
121
|
-
npm: @npmcli/arborist (
|
|
108
|
+
npm: @npmcli/arborist (preferred) or @cyclonedx/cyclonedx-npm
|
|
122
109
|
yarn-classic: @yarnpkg/lockfile
|
|
123
110
|
yarn-berry: @yarnpkg/parsers
|
|
124
|
-
pnpm: js-yaml
|
|
111
|
+
pnpm: @pnpm/lockfile.fs (preferred) or js-yaml
|
|
112
|
+
|
|
113
|
+
Result types:
|
|
114
|
+
✓ equinumerous Same packages in both (exact match)
|
|
115
|
+
⊃ SUPERSET flatlock found MORE packages (expected for pnpm)
|
|
116
|
+
❌ MISMATCH Unexpected difference (comparison found packages flatlock missed)
|
|
117
|
+
|
|
118
|
+
Note on pnpm supersets:
|
|
119
|
+
flatlock performs full reachability analysis on lockfiles, finding all
|
|
120
|
+
transitive dependencies. pnpm's official tools don't enumerate all reachable
|
|
121
|
+
packages - they omit some transitive deps from their API output. When flatlock
|
|
122
|
+
finds MORE packages than pnpm, this is expected and correct behavior.
|
|
125
123
|
|
|
126
124
|
Examples:
|
|
127
125
|
flatlock-cmp package-lock.json
|
|
@@ -153,6 +151,7 @@ Examples:
|
|
|
153
151
|
let fileCount = 0;
|
|
154
152
|
let errorCount = 0;
|
|
155
153
|
let matchCount = 0;
|
|
154
|
+
let supersetCount = 0; // flatlock found more (expected for pnpm reachability)
|
|
156
155
|
let mismatchCount = 0;
|
|
157
156
|
|
|
158
157
|
for (const file of files) {
|
|
@@ -175,44 +174,61 @@ Examples:
|
|
|
175
174
|
if (!values.quiet) {
|
|
176
175
|
console.log(`\n⚠️ ${result.path}`);
|
|
177
176
|
console.log(` flatlock: ${result.flatlockCount} packages`);
|
|
178
|
-
console.log(` ${result.
|
|
177
|
+
console.log(` ${result.source}: unavailable`);
|
|
179
178
|
}
|
|
180
179
|
continue;
|
|
181
180
|
}
|
|
182
181
|
|
|
183
182
|
totalComparison += result.comparisonCount;
|
|
184
183
|
|
|
185
|
-
if (result.
|
|
184
|
+
if (result.equinumerous) {
|
|
186
185
|
matchCount++;
|
|
187
186
|
if (!values.quiet) {
|
|
188
187
|
const wsNote = result.workspaceCount > 0 ? ` (${result.workspaceCount} workspaces excluded)` : '';
|
|
189
188
|
console.log(`✓ ${result.path}${wsNote}`);
|
|
190
|
-
console.log(` count: flatlock=${result.flatlockCount} ${result.
|
|
191
|
-
console.log(` sets:
|
|
189
|
+
console.log(` count: flatlock=${result.flatlockCount} ${result.source}=${result.comparisonCount}`);
|
|
190
|
+
console.log(` sets: equinumerous`);
|
|
192
191
|
}
|
|
193
192
|
} else {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
console.log(`
|
|
193
|
+
// Determine if this is a "superset" (flatlock found more, expected for pnpm)
|
|
194
|
+
// or a true "mismatch" (comparison found packages flatlock missed)
|
|
195
|
+
const isPnpm = result.type === 'pnpm' || result.path.includes('pnpm-lock');
|
|
196
|
+
const isSuperset = result.onlyInFlatlock.length > 0 && result.onlyInComparison.length === 0;
|
|
197
|
+
|
|
198
|
+
if (isPnpm && isSuperset) {
|
|
199
|
+
// Expected behavior: flatlock's reachability analysis found more packages
|
|
200
|
+
supersetCount++;
|
|
201
|
+
if (!values.quiet) {
|
|
202
|
+
const wsNote = result.workspaceCount > 0 ? ` (${result.workspaceCount} workspaces excluded)` : '';
|
|
203
|
+
console.log(`⊃ ${result.path}${wsNote}`);
|
|
204
|
+
console.log(` count: flatlock=${result.flatlockCount} ${result.source}=${result.comparisonCount}`);
|
|
205
|
+
console.log(` sets: SUPERSET (+${result.onlyInFlatlock.length} reachable deps)`);
|
|
206
|
+
console.log(` note: flatlock's reachability analysis found transitive deps pnpm omits`);
|
|
206
207
|
}
|
|
207
|
-
}
|
|
208
|
+
} else {
|
|
209
|
+
mismatchCount++;
|
|
210
|
+
console.log(`\n❌ ${result.path}`);
|
|
211
|
+
console.log(` count: flatlock=${result.flatlockCount} ${result.source}=${result.comparisonCount}`);
|
|
212
|
+
console.log(` sets: MISMATCH`);
|
|
208
213
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
214
|
+
if (result.onlyInFlatlock.length > 0) {
|
|
215
|
+
console.log(` only in flatlock (${result.onlyInFlatlock.length}):`);
|
|
216
|
+
for (const pkg of result.onlyInFlatlock.slice(0, 10)) {
|
|
217
|
+
console.log(` + ${pkg}`);
|
|
218
|
+
}
|
|
219
|
+
if (result.onlyInFlatlock.length > 10) {
|
|
220
|
+
console.log(` ... and ${result.onlyInFlatlock.length - 10} more`);
|
|
221
|
+
}
|
|
213
222
|
}
|
|
214
|
-
|
|
215
|
-
|
|
223
|
+
|
|
224
|
+
if (result.onlyInComparison.length > 0) {
|
|
225
|
+
console.log(` only in ${result.source} (${result.onlyInComparison.length}):`);
|
|
226
|
+
for (const pkg of result.onlyInComparison.slice(0, 10)) {
|
|
227
|
+
console.log(` - ${pkg}`);
|
|
228
|
+
}
|
|
229
|
+
if (result.onlyInComparison.length > 10) {
|
|
230
|
+
console.log(` ... and ${result.onlyInComparison.length - 10} more`);
|
|
231
|
+
}
|
|
216
232
|
}
|
|
217
233
|
}
|
|
218
234
|
}
|
|
@@ -220,7 +236,13 @@ Examples:
|
|
|
220
236
|
|
|
221
237
|
// Summary
|
|
222
238
|
console.log('\n' + '='.repeat(70));
|
|
223
|
-
|
|
239
|
+
const summaryParts = [`${fileCount} files`, `${matchCount} equinumerous`];
|
|
240
|
+
if (supersetCount > 0) {
|
|
241
|
+
summaryParts.push(`${supersetCount} supersets`);
|
|
242
|
+
}
|
|
243
|
+
summaryParts.push(`${mismatchCount} mismatches`, `${errorCount} errors`);
|
|
244
|
+
console.log(`SUMMARY: ${summaryParts.join(', ')}`);
|
|
245
|
+
|
|
224
246
|
console.log(` flatlock total: ${totalFlatlock.toString().padStart(8)} packages`);
|
|
225
247
|
if (totalComparison > 0) {
|
|
226
248
|
console.log(` comparison total: ${totalComparison.toString().padStart(8)} packages`);
|
|
@@ -228,8 +250,12 @@ Examples:
|
|
|
228
250
|
if (totalWorkspaces > 0) {
|
|
229
251
|
console.log(` workspaces: ${totalWorkspaces.toString().padStart(8)} excluded (local/workspace refs)`);
|
|
230
252
|
}
|
|
253
|
+
if (supersetCount > 0) {
|
|
254
|
+
console.log(` supersets: ${supersetCount.toString().padStart(8)} (flatlock found more via reachability)`);
|
|
255
|
+
}
|
|
231
256
|
|
|
232
|
-
// Exit with error
|
|
257
|
+
// Exit with error only for true mismatches (not supersets)
|
|
258
|
+
// Supersets are expected: flatlock's reachability analysis is more thorough
|
|
233
259
|
if (mismatchCount > 0) {
|
|
234
260
|
process.exit(1);
|
|
235
261
|
}
|
package/dist/compare.d.ts
CHANGED
|
@@ -14,11 +14,25 @@ export function compare(filepath: string, options?: CompareOptions): Promise<Com
|
|
|
14
14
|
export function compareAll(filepaths: string[], options?: CompareOptions): AsyncGenerator<ComparisonResult & {
|
|
15
15
|
filepath: string;
|
|
16
16
|
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Check which optional comparison parsers are available
|
|
19
|
+
* @returns {Promise<{ arborist: boolean, cyclonedx: boolean, pnpmLockfileFs: boolean, yarnCore: boolean }>}
|
|
20
|
+
*/
|
|
21
|
+
export function getAvailableParsers(): Promise<{
|
|
22
|
+
arborist: boolean;
|
|
23
|
+
cyclonedx: boolean;
|
|
24
|
+
pnpmLockfileFs: boolean;
|
|
25
|
+
yarnCore: boolean;
|
|
26
|
+
}>;
|
|
17
27
|
export type CompareOptions = {
|
|
18
28
|
/**
|
|
19
|
-
* - Temp directory for Arborist (npm only)
|
|
29
|
+
* - Temp directory for Arborist/CycloneDX (npm only)
|
|
20
30
|
*/
|
|
21
31
|
tmpDir?: string;
|
|
32
|
+
/**
|
|
33
|
+
* - Workspace paths for CycloneDX (-w flag)
|
|
34
|
+
*/
|
|
35
|
+
workspace?: string[];
|
|
22
36
|
};
|
|
23
37
|
export type ComparisonResult = {
|
|
24
38
|
/**
|
|
@@ -26,9 +40,13 @@ export type ComparisonResult = {
|
|
|
26
40
|
*/
|
|
27
41
|
type: string;
|
|
28
42
|
/**
|
|
29
|
-
* -
|
|
43
|
+
* - Comparison source used (e.g., '@npmcli/arborist', '@cyclonedx/cyclonedx-npm')
|
|
30
44
|
*/
|
|
31
|
-
|
|
45
|
+
source?: string;
|
|
46
|
+
/**
|
|
47
|
+
* - Whether flatlock and comparison have same cardinality
|
|
48
|
+
*/
|
|
49
|
+
equinumerous: boolean | null;
|
|
32
50
|
/**
|
|
33
51
|
* - Number of packages found by flatlock
|
|
34
52
|
*/
|
|
@@ -59,5 +77,9 @@ export type PackagesResult = {
|
|
|
59
77
|
* - Number of workspace packages skipped
|
|
60
78
|
*/
|
|
61
79
|
workspaceCount: number;
|
|
80
|
+
/**
|
|
81
|
+
* - Comparison source used
|
|
82
|
+
*/
|
|
83
|
+
source: string;
|
|
62
84
|
};
|
|
63
85
|
//# sourceMappingURL=compare.d.ts.map
|
package/dist/compare.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../src/compare.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../src/compare.js"],"names":[],"mappings":"AAyhBA;;;;;GAKG;AACH,kCAJW,MAAM,YACN,cAAc,GACZ,OAAO,CAAC,gBAAgB,CAAC,CA8CrC;AAED;;;;;GAKG;AACH,sCAJW,MAAM,EAAE,YACR,cAAc,GACZ,cAAc,CAAC,gBAAgB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAMnE;AAED;;;GAGG;AACH,uCAFa,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,CAgB1G;;;;;aAnhBa,MAAM;;;;gBACN,MAAM,EAAE;;;;;;UAKR,MAAM;;;;aACN,MAAM;;;;kBACN,OAAO,GAAG,IAAI;;;;mBACd,MAAM;;;;sBACN,MAAM;;;;qBACN,MAAM;;;;qBACN,MAAM,EAAE;;;;uBACR,MAAM,EAAE;;;;;;cAKR,GAAG,CAAC,MAAM,CAAC;;;;oBACX,MAAM;;;;YACN,MAAM"}
|
package/dist/detect.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.js"],"names":[],"mappings":"AA6FA;;;;;;;;;;;;;;GAcG;AACH,+CALG;IAAyB,IAAI;IACJ,OAAO;CAChC,GAAU,YAAY,CAgDxB;AArJD;;GAEG;AAEH;;GAEG;AACH;;;;;GAKG;2BAXU,KAAK,GAAG,MAAM,GAAG,cAAc,GAAG,YAAY"}
|
package/dist/index.d.ts
CHANGED
|
@@ -65,6 +65,8 @@ import { fromPackageLock } from './parsers/index.js';
|
|
|
65
65
|
import { fromPnpmLock } from './parsers/index.js';
|
|
66
66
|
import { fromYarnClassicLock } from './parsers/index.js';
|
|
67
67
|
import { fromYarnBerryLock } from './parsers/index.js';
|
|
68
|
-
|
|
68
|
+
import { FlatlockSet } from './set.js';
|
|
69
|
+
export { Type, detectType, Ok, Err, fromPackageLock, fromPnpmLock, fromYarnClassicLock, fromYarnBerryLock, FlatlockSet };
|
|
70
|
+
export { compare, compareAll, getAvailableParsers } from "./compare.js";
|
|
69
71
|
export { parseNpmKey, parsePnpmKey, parseYarnBerryKey, parseYarnClassicKey } from "./parsers/index.js";
|
|
70
72
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AAgCA;;;;;GAKG;AACH,+BAJW,MAAM,YACN,MAAM,GACJ,cAAc,CAAC,UAAU,CAAC,CAOtC;AAED;;;;;;;GAOG;AACH,oCANW,MAAM,YAEd;IAAyB,IAAI;IACE,IAAI;CACnC,GAAU,SAAS,CAAC,UAAU,CAAC,CA0BjC;AAED;;;;;GAKG;AACH,kCAJW,MAAM,YACN,YAAY,GACV,OAAO,CAAC,OAAO,aAAa,EAAE,MAAM,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,CAS7E;AAED;;;;;GAKG;AACH,uCAJW,MAAM,YACN,YAAY,GACV,OAAO,aAAa,EAAE,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAW/D;AAED;;;;;GAKG;AACH,sCAJW,MAAM,YACN,MAAM,GACJ,SAAS,CAAC,UAAU,CAAC,CAUjC;AAED;;;;;GAKG;AACH,uCAJW,MAAM,YACN,MAAM,GACJ,OAAO,CAAC,UAAU,EAAE,CAAC,CAmBjC;2BA3Ia,OAAO,aAAa,EAAE,YAAY;yBAClC,OAAO,kBAAkB,EAAE,UAAU;;;;;WAIrC,MAAM;;;;WACN,YAAY;;qBAhBO,aAAa;2BAAb,aAAa;mBAOtB,aAAa;oBAAb,aAAa;gCAD9B,oBAAoB;6BAApB,oBAAoB;oCAApB,oBAAoB;kCAApB,oBAAoB;4BAEC,UAAU"}
|
package/dist/parsers/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { fromPackageLock, parseLockfileKey as parseNpmKey } from "./npm.js";
|
|
2
2
|
export { fromPnpmLock, parseLockfileKey as parsePnpmKey } from "./pnpm.js";
|
|
3
|
-
export { fromYarnBerryLock, parseLockfileKey as parseYarnBerryKey } from "./yarn-berry.js";
|
|
4
|
-
export { fromYarnClassicLock, parseLockfileKey as parseYarnClassicKey } from "./yarn-classic.js";
|
|
3
|
+
export { fromYarnBerryLock, parseLockfileKey as parseYarnBerryKey, parseResolution as parseYarnBerryResolution } from "./yarn-berry.js";
|
|
4
|
+
export { fromYarnClassicLock, parseLockfileKey as parseYarnClassicKey, parseYarnClassic } from "./yarn-classic.js";
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/parsers/npm.d.ts
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @typedef {Object} Dependency
|
|
3
|
-
* @property {string} name - Package name
|
|
4
|
-
* @property {string} version - Resolved version
|
|
5
|
-
* @property {string} [integrity] - Integrity hash
|
|
6
|
-
* @property {string} [resolved] - Resolution URL
|
|
7
|
-
* @property {boolean} [link] - True if this is a symlink
|
|
8
|
-
*/
|
|
1
|
+
/** @typedef {import('./types.js').Dependency} Dependency */
|
|
9
2
|
/**
|
|
10
3
|
* LIMITATION: Workspace symlinks are not yielded
|
|
11
4
|
*
|
|
@@ -41,42 +34,76 @@
|
|
|
41
34
|
* pkg := name (unscoped)
|
|
42
35
|
* | @scope/name (scoped)
|
|
43
36
|
*
|
|
44
|
-
* Examples:
|
|
45
|
-
* - node_modules/lodash → "lodash"
|
|
46
|
-
* - node_modules/@babel/core → "@babel/core"
|
|
47
|
-
* - node_modules/foo/node_modules/@scope/bar → "@scope/bar"
|
|
48
|
-
*
|
|
49
37
|
* @param {string} path - Lockfile path key
|
|
50
38
|
* @returns {string} Package name
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* // Simple unscoped package
|
|
42
|
+
* parseLockfileKey('node_modules/lodash')
|
|
43
|
+
* // => 'lodash'
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* // Scoped package
|
|
47
|
+
* parseLockfileKey('node_modules/@babel/core')
|
|
48
|
+
* // => '@babel/core'
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* // Nested dependency (hoisted conflict resolution)
|
|
52
|
+
* parseLockfileKey('node_modules/foo/node_modules/bar')
|
|
53
|
+
* // => 'bar'
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* // Nested scoped dependency
|
|
57
|
+
* parseLockfileKey('node_modules/foo/node_modules/@scope/bar')
|
|
58
|
+
* // => '@scope/bar'
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* // Deeply nested dependency
|
|
62
|
+
* parseLockfileKey('node_modules/a/node_modules/b/node_modules/c')
|
|
63
|
+
* // => 'c'
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* // Deeply nested scoped dependency
|
|
67
|
+
* parseLockfileKey('node_modules/a/node_modules/@types/node')
|
|
68
|
+
* // => '@types/node'
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* // Workspace package path (definition)
|
|
72
|
+
* parseLockfileKey('packages/my-lib')
|
|
73
|
+
* // => 'my-lib'
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* // Workspace nested dependency
|
|
77
|
+
* parseLockfileKey('packages/my-lib/node_modules/lodash')
|
|
78
|
+
* // => 'lodash'
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* // Workspace nested scoped dependency
|
|
82
|
+
* parseLockfileKey('packages/my-lib/node_modules/@types/react')
|
|
83
|
+
* // => '@types/react'
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* // Package with hyphenated name
|
|
87
|
+
* parseLockfileKey('node_modules/string-width')
|
|
88
|
+
* // => 'string-width'
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* // Scoped package with hyphenated name
|
|
92
|
+
* parseLockfileKey('node_modules/@emotion/styled')
|
|
93
|
+
* // => '@emotion/styled'
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* // Complex nested path
|
|
97
|
+
* parseLockfileKey('node_modules/@babel/core/node_modules/@babel/helper-compilation-targets')
|
|
98
|
+
* // => '@babel/helper-compilation-targets'
|
|
51
99
|
*/
|
|
52
100
|
export function parseLockfileKey(path: string): string;
|
|
53
101
|
/**
|
|
54
102
|
* Parse npm package-lock.json (v1, v2, v3)
|
|
55
|
-
* @param {string}
|
|
103
|
+
* @param {string | object} input - Lockfile content string or pre-parsed object
|
|
56
104
|
* @param {Object} [_options] - Parser options (unused, reserved for future use)
|
|
57
105
|
* @returns {Generator<Dependency>}
|
|
58
106
|
*/
|
|
59
|
-
export function fromPackageLock(
|
|
60
|
-
export type Dependency =
|
|
61
|
-
/**
|
|
62
|
-
* - Package name
|
|
63
|
-
*/
|
|
64
|
-
name: string;
|
|
65
|
-
/**
|
|
66
|
-
* - Resolved version
|
|
67
|
-
*/
|
|
68
|
-
version: string;
|
|
69
|
-
/**
|
|
70
|
-
* - Integrity hash
|
|
71
|
-
*/
|
|
72
|
-
integrity?: string;
|
|
73
|
-
/**
|
|
74
|
-
* - Resolution URL
|
|
75
|
-
*/
|
|
76
|
-
resolved?: string;
|
|
77
|
-
/**
|
|
78
|
-
* - True if this is a symlink
|
|
79
|
-
*/
|
|
80
|
-
link?: boolean;
|
|
81
|
-
};
|
|
107
|
+
export function fromPackageLock(input: string | object, _options?: Object): Generator<Dependency>;
|
|
108
|
+
export type Dependency = import("./types.js").Dependency;
|
|
82
109
|
//# sourceMappingURL=npm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"npm.d.ts","sourceRoot":"","sources":["../../src/parsers/npm.js"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"npm.d.ts","sourceRoot":"","sources":["../../src/parsers/npm.js"],"names":[],"mappings":"AAAA,4DAA4D;AAE5D;;;;;;;;;;;GAWG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqFG;AACH,uCA/DW,MAAM,GACJ,MAAM,CAoElB;AAED;;;;;GAKG;AACH,uCAJW,MAAM,GAAG,MAAM,aACf,MAAM,GACJ,SAAS,CAAC,UAAU,CAAC,CA6BjC;yBA9Ia,OAAO,YAAY,EAAE,UAAU"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Version detection for pnpm lockfiles
|
|
3
|
+
*
|
|
4
|
+
* Detects the era and version of pnpm lockfiles including:
|
|
5
|
+
* - shrinkwrap.yaml (v3/v4) from 2016-2019
|
|
6
|
+
* - pnpm-lock.yaml v5.x (2019-2022)
|
|
7
|
+
* - pnpm-lock.yaml v6.0 (2023)
|
|
8
|
+
* - pnpm-lock.yaml v9.0 (2024+)
|
|
9
|
+
*
|
|
10
|
+
* @module flatlock/parsers/pnpm/detect
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {'shrinkwrap'|'v5'|'v5-inline'|'v6'|'v9'|'unknown'} LockfileEra
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {Object} DetectedVersion
|
|
17
|
+
* @property {LockfileEra} era - The lockfile era/format family
|
|
18
|
+
* @property {string|number} version - The raw version from the lockfile
|
|
19
|
+
* @property {boolean} isShrinkwrap - True if this is a shrinkwrap.yaml file
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Detect the version and era of a pnpm lockfile.
|
|
23
|
+
*
|
|
24
|
+
* Version detection rules:
|
|
25
|
+
* - If `shrinkwrapVersion` exists: shrinkwrap era (v3/v4)
|
|
26
|
+
* - If `lockfileVersion` is a number: v5 era
|
|
27
|
+
* - If `lockfileVersion` is '5.4-inlineSpecifiers': v5-inline era
|
|
28
|
+
* - If `lockfileVersion` starts with '6': v6 era
|
|
29
|
+
* - If `lockfileVersion` starts with '9': v9 era
|
|
30
|
+
*
|
|
31
|
+
* @param {Object} lockfile - Parsed pnpm lockfile object
|
|
32
|
+
* @param {string|number} [lockfile.lockfileVersion] - The lockfile version field
|
|
33
|
+
* @param {number} [lockfile.shrinkwrapVersion] - The shrinkwrap version field (v3/v4)
|
|
34
|
+
* @param {number} [lockfile.shrinkwrapMinorVersion] - Minor version for shrinkwrap
|
|
35
|
+
* @returns {DetectedVersion} The detected version information
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* // shrinkwrap.yaml v3
|
|
39
|
+
* detectVersion({ shrinkwrapVersion: 3 })
|
|
40
|
+
* // => { era: 'shrinkwrap', version: 3, isShrinkwrap: true }
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* // pnpm-lock.yaml v5.4
|
|
44
|
+
* detectVersion({ lockfileVersion: 5.4 })
|
|
45
|
+
* // => { era: 'v5', version: 5.4, isShrinkwrap: false }
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* // pnpm-lock.yaml v6.0
|
|
49
|
+
* detectVersion({ lockfileVersion: '6.0' })
|
|
50
|
+
* // => { era: 'v6', version: '6.0', isShrinkwrap: false }
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* // pnpm-lock.yaml v9.0
|
|
54
|
+
* detectVersion({ lockfileVersion: '9.0' })
|
|
55
|
+
* // => { era: 'v9', version: '9.0', isShrinkwrap: false }
|
|
56
|
+
*/
|
|
57
|
+
export function detectVersion(lockfile: {
|
|
58
|
+
lockfileVersion?: string | number | undefined;
|
|
59
|
+
shrinkwrapVersion?: number | undefined;
|
|
60
|
+
shrinkwrapMinorVersion?: number | undefined;
|
|
61
|
+
}): DetectedVersion;
|
|
62
|
+
/**
|
|
63
|
+
* Check if a lockfile uses the v6+ package key format (name@version).
|
|
64
|
+
*
|
|
65
|
+
* v5 and earlier use: /name/version or /@scope/name/version
|
|
66
|
+
* v6+ use: /name@version or /@scope/name@version
|
|
67
|
+
* v9+ use: name@version (no leading slash)
|
|
68
|
+
*
|
|
69
|
+
* @param {DetectedVersion} detected - The detected version info
|
|
70
|
+
* @returns {boolean} True if the lockfile uses @ separator for name@version
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* usesAtSeparator({ era: 'v5', version: 5.4 }) // => false
|
|
74
|
+
* usesAtSeparator({ era: 'v6', version: '6.0' }) // => true
|
|
75
|
+
* usesAtSeparator({ era: 'v9', version: '9.0' }) // => true
|
|
76
|
+
*/
|
|
77
|
+
export function usesAtSeparator(detected: DetectedVersion): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Check if a lockfile uses the packages/snapshots split (v9+).
|
|
80
|
+
*
|
|
81
|
+
* v9 separates package metadata (packages) from dependency relationships (snapshots).
|
|
82
|
+
*
|
|
83
|
+
* @param {DetectedVersion} detected - The detected version info
|
|
84
|
+
* @returns {boolean} True if the lockfile has packages/snapshots split
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* usesSnapshotsSplit({ era: 'v6', version: '6.0' }) // => false
|
|
88
|
+
* usesSnapshotsSplit({ era: 'v9', version: '9.0' }) // => true
|
|
89
|
+
*/
|
|
90
|
+
export function usesSnapshotsSplit(detected: DetectedVersion): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Check if a lockfile uses inline specifiers.
|
|
93
|
+
*
|
|
94
|
+
* v5.4-inlineSpecifiers and v6+ use inline specifiers in importers.
|
|
95
|
+
* Earlier versions have a separate `specifiers` block.
|
|
96
|
+
*
|
|
97
|
+
* @param {DetectedVersion} detected - The detected version info
|
|
98
|
+
* @returns {boolean} True if specifiers are inlined
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* usesInlineSpecifiers({ era: 'v5', version: 5.4 }) // => false
|
|
102
|
+
* usesInlineSpecifiers({ era: 'v5-inline', version: '5.4-inlineSpecifiers' }) // => true
|
|
103
|
+
* usesInlineSpecifiers({ era: 'v6', version: '6.0' }) // => true
|
|
104
|
+
*/
|
|
105
|
+
export function usesInlineSpecifiers(detected: DetectedVersion): boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Check if package keys have a leading slash.
|
|
108
|
+
*
|
|
109
|
+
* v5 and v6 use leading slash: /name/version or /name@version
|
|
110
|
+
* v9 omits leading slash: name@version
|
|
111
|
+
*
|
|
112
|
+
* @param {DetectedVersion} detected - The detected version info
|
|
113
|
+
* @returns {boolean} True if package keys have leading slash
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* hasLeadingSlash({ era: 'v5', version: 5.4 }) // => true
|
|
117
|
+
* hasLeadingSlash({ era: 'v6', version: '6.0' }) // => true
|
|
118
|
+
* hasLeadingSlash({ era: 'v9', version: '9.0' }) // => false
|
|
119
|
+
*/
|
|
120
|
+
export function hasLeadingSlash(detected: DetectedVersion): boolean;
|
|
121
|
+
export type LockfileEra = "shrinkwrap" | "v5" | "v5-inline" | "v6" | "v9" | "unknown";
|
|
122
|
+
export type DetectedVersion = {
|
|
123
|
+
/**
|
|
124
|
+
* - The lockfile era/format family
|
|
125
|
+
*/
|
|
126
|
+
era: LockfileEra;
|
|
127
|
+
/**
|
|
128
|
+
* - The raw version from the lockfile
|
|
129
|
+
*/
|
|
130
|
+
version: string | number;
|
|
131
|
+
/**
|
|
132
|
+
* - True if this is a shrinkwrap.yaml file
|
|
133
|
+
*/
|
|
134
|
+
isShrinkwrap: boolean;
|
|
135
|
+
};
|
|
136
|
+
//# sourceMappingURL=detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../../src/parsers/pnpm/detect.js"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;GAEG;AAEH;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wCAzBG;IAAiC,eAAe;IACtB,iBAAiB;IACjB,sBAAsB;CAChD,GAAU,eAAe,CAyF3B;AAED;;;;;;;;;;;;;;GAcG;AACH,0CARW,eAAe,GACb,OAAO,CASnB;AAED;;;;;;;;;;;GAWG;AACH,6CAPW,eAAe,GACb,OAAO,CAQnB;AAED;;;;;;;;;;;;;GAaG;AACH,+CARW,eAAe,GACb,OAAO,CASnB;AAED;;;;;;;;;;;;;GAaG;AACH,0CARW,eAAe,GACb,OAAO,CASnB;0BAxLY,YAAY,GAAC,IAAI,GAAC,WAAW,GAAC,IAAI,GAAC,IAAI,GAAC,SAAS;;;;;SAKhD,WAAW;;;;aACX,MAAM,GAAC,MAAM;;;;kBACb,OAAO"}
|