flatlock 1.2.0 → 1.4.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 +42 -1
- package/bin/flatcover.js +547 -0
- package/bin/flatlock-cmp.js +2 -2
- package/bin/flatlock.js +158 -0
- package/dist/compare.d.ts.map +1 -1
- package/dist/parsers/index.d.ts +3 -3
- package/dist/parsers/npm.d.ts +45 -0
- package/dist/parsers/npm.d.ts.map +1 -1
- package/dist/parsers/pnpm/index.d.ts +34 -0
- package/dist/parsers/pnpm/index.d.ts.map +1 -1
- package/dist/parsers/yarn-berry.d.ts +43 -0
- package/dist/parsers/yarn-berry.d.ts.map +1 -1
- package/dist/set.d.ts +55 -6
- package/dist/set.d.ts.map +1 -1
- package/package.json +21 -5
- package/src/compare.js +5 -7
- package/src/parsers/index.js +14 -2
- package/src/parsers/npm.js +82 -0
- package/src/parsers/pnpm/index.js +70 -0
- package/src/parsers/yarn-berry.js +88 -0
- package/src/set.js +730 -41
package/bin/flatlock.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* flatlock - Get dependencies from a lockfile
|
|
4
|
+
*
|
|
5
|
+
* For monorepo workspaces, outputs the production dependencies of a workspace.
|
|
6
|
+
* For standalone packages, outputs all production dependencies.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* flatlock <lockfile> # all deps (names only)
|
|
10
|
+
* flatlock <lockfile> --specs # name@version
|
|
11
|
+
* flatlock <lockfile> --json # JSON array
|
|
12
|
+
* flatlock <lockfile> --specs --json # JSON with versions
|
|
13
|
+
* flatlock <lockfile> --specs --ndjson # streaming NDJSON
|
|
14
|
+
* flatlock <lockfile> --full --ndjson # full metadata streaming
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { parseArgs } from 'node:util';
|
|
18
|
+
import { readFileSync } from 'node:fs';
|
|
19
|
+
import { dirname, join } from 'node:path';
|
|
20
|
+
import { FlatlockSet } from '../src/set.js';
|
|
21
|
+
|
|
22
|
+
const { values, positionals } = parseArgs({
|
|
23
|
+
options: {
|
|
24
|
+
workspace: { type: 'string', short: 'w' },
|
|
25
|
+
dev: { type: 'boolean', default: false },
|
|
26
|
+
peer: { type: 'boolean', default: true },
|
|
27
|
+
specs: { type: 'boolean', short: 's', default: false },
|
|
28
|
+
json: { type: 'boolean', default: false },
|
|
29
|
+
ndjson: { type: 'boolean', default: false },
|
|
30
|
+
full: { type: 'boolean', default: false },
|
|
31
|
+
help: { type: 'boolean', short: 'h' }
|
|
32
|
+
},
|
|
33
|
+
allowPositionals: true
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
if (values.help || positionals.length === 0) {
|
|
37
|
+
console.log(`flatlock - Get dependencies from a lockfile
|
|
38
|
+
|
|
39
|
+
Usage:
|
|
40
|
+
flatlock <lockfile>
|
|
41
|
+
flatlock <lockfile> --workspace <path>
|
|
42
|
+
|
|
43
|
+
Options:
|
|
44
|
+
-w, --workspace <path> Workspace path within monorepo
|
|
45
|
+
-s, --specs Include version (name@version or {name,version})
|
|
46
|
+
--json Output as JSON array
|
|
47
|
+
--ndjson Output as newline-delimited JSON (streaming)
|
|
48
|
+
--full Include all metadata (integrity, resolved)
|
|
49
|
+
--dev Include dev dependencies (default: false)
|
|
50
|
+
--peer Include peer dependencies (default: true)
|
|
51
|
+
-h, --help Show this help
|
|
52
|
+
|
|
53
|
+
Output formats:
|
|
54
|
+
(default) package names, one per line
|
|
55
|
+
--specs package@version, one per line
|
|
56
|
+
--json ["package", ...]
|
|
57
|
+
--specs --json [{"name":"...","version":"..."}, ...]
|
|
58
|
+
--full --json [{"name":"...","version":"...","integrity":"...","resolved":"..."}, ...]
|
|
59
|
+
--ndjson "package" per line
|
|
60
|
+
--specs --ndjson {"name":"...","version":"..."} per line
|
|
61
|
+
--full --ndjson {"name":"...","version":"...","integrity":"...","resolved":"..."} per line
|
|
62
|
+
|
|
63
|
+
Examples:
|
|
64
|
+
flatlock package-lock.json
|
|
65
|
+
flatlock package-lock.json --specs
|
|
66
|
+
flatlock package-lock.json --specs --json
|
|
67
|
+
flatlock package-lock.json --full --ndjson | jq -c 'select(.name | startswith("@babel"))'
|
|
68
|
+
flatlock pnpm-lock.yaml -w packages/core -s --ndjson`);
|
|
69
|
+
process.exit(values.help ? 0 : 1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (values.json && values.ndjson) {
|
|
73
|
+
console.error('Error: --json and --ndjson are mutually exclusive');
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// --full implies --specs
|
|
78
|
+
if (values.full) {
|
|
79
|
+
values.specs = true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const lockfilePath = positionals[0];
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Format a single dependency based on output options
|
|
86
|
+
* @param {{ name: string, version: string, integrity?: string, resolved?: string }} dep
|
|
87
|
+
* @param {{ specs: boolean, full: boolean }} options
|
|
88
|
+
* @returns {string | object}
|
|
89
|
+
*/
|
|
90
|
+
function formatDep(dep, { specs, full }) {
|
|
91
|
+
if (full) {
|
|
92
|
+
const obj = { name: dep.name, version: dep.version };
|
|
93
|
+
if (dep.integrity) obj.integrity = dep.integrity;
|
|
94
|
+
if (dep.resolved) obj.resolved = dep.resolved;
|
|
95
|
+
return obj;
|
|
96
|
+
}
|
|
97
|
+
if (specs) {
|
|
98
|
+
return { name: dep.name, version: dep.version };
|
|
99
|
+
}
|
|
100
|
+
return dep.name;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Output dependencies in the requested format
|
|
105
|
+
* @param {Iterable<{ name: string, version: string, integrity?: string, resolved?: string }>} deps
|
|
106
|
+
* @param {{ specs: boolean, json: boolean, ndjson: boolean, full: boolean }} options
|
|
107
|
+
*/
|
|
108
|
+
function outputDeps(deps, { specs, json, ndjson, full }) {
|
|
109
|
+
const sorted = [...deps].sort((a, b) => a.name.localeCompare(b.name));
|
|
110
|
+
|
|
111
|
+
if (json) {
|
|
112
|
+
const data = sorted.map(d => formatDep(d, { specs, full }));
|
|
113
|
+
console.log(JSON.stringify(data, null, 2));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (ndjson) {
|
|
118
|
+
for (const d of sorted) {
|
|
119
|
+
console.log(JSON.stringify(formatDep(d, { specs, full })));
|
|
120
|
+
}
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Plain text
|
|
125
|
+
for (const d of sorted) {
|
|
126
|
+
console.log(specs ? `${d.name}@${d.version}` : d.name);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
const lockfile = await FlatlockSet.fromPath(lockfilePath);
|
|
132
|
+
let deps;
|
|
133
|
+
|
|
134
|
+
if (values.workspace) {
|
|
135
|
+
const repoDir = dirname(lockfilePath);
|
|
136
|
+
const workspacePkgPath = join(repoDir, values.workspace, 'package.json');
|
|
137
|
+
const workspacePkg = JSON.parse(readFileSync(workspacePkgPath, 'utf8'));
|
|
138
|
+
|
|
139
|
+
deps = await lockfile.dependenciesOf(workspacePkg, {
|
|
140
|
+
workspacePath: values.workspace,
|
|
141
|
+
repoDir,
|
|
142
|
+
dev: values.dev,
|
|
143
|
+
peer: values.peer
|
|
144
|
+
});
|
|
145
|
+
} else {
|
|
146
|
+
deps = lockfile;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
outputDeps(deps, {
|
|
150
|
+
specs: values.specs,
|
|
151
|
+
json: values.json,
|
|
152
|
+
ndjson: values.ndjson,
|
|
153
|
+
full: values.full
|
|
154
|
+
});
|
|
155
|
+
} catch (err) {
|
|
156
|
+
console.error(`Error: ${err.message}`);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
package/dist/compare.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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,
|
|
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,CA4CrC;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;;;;;aAjhBa,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/parsers/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { fromPackageLock, parseLockfileKey as parseNpmKey } from "./npm.js";
|
|
2
|
-
export { fromPnpmLock, parseLockfileKey as parsePnpmKey } from "./pnpm.js";
|
|
3
|
-
export { fromYarnBerryLock, parseLockfileKey as parseYarnBerryKey, parseResolution as parseYarnBerryResolution } from "./yarn-berry.js";
|
|
1
|
+
export { buildWorkspacePackages as buildNpmWorkspacePackages, extractWorkspacePaths as extractNpmWorkspacePaths, fromPackageLock, parseLockfileKey as parseNpmKey } from "./npm.js";
|
|
2
|
+
export { buildWorkspacePackages as buildPnpmWorkspacePackages, extractWorkspacePaths as extractPnpmWorkspacePaths, fromPnpmLock, parseLockfileKey as parsePnpmKey } from "./pnpm.js";
|
|
3
|
+
export { buildWorkspacePackages as buildYarnBerryWorkspacePackages, extractWorkspacePaths as extractYarnBerryWorkspacePaths, fromYarnBerryLock, parseLockfileKey as parseYarnBerryKey, parseResolution as parseYarnBerryResolution } from "./yarn-berry.js";
|
|
4
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,4 +1,13 @@
|
|
|
1
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
|
+
*/
|
|
2
11
|
/**
|
|
3
12
|
* LIMITATION: Workspace symlinks are not yielded
|
|
4
13
|
*
|
|
@@ -105,5 +114,41 @@ export function parseLockfileKey(path: string): string;
|
|
|
105
114
|
* @returns {Generator<Dependency>}
|
|
106
115
|
*/
|
|
107
116
|
export function fromPackageLock(input: string | object, _options?: Object): Generator<Dependency>;
|
|
117
|
+
/**
|
|
118
|
+
* Extract workspace paths from npm lockfile.
|
|
119
|
+
*
|
|
120
|
+
* npm workspace packages are entries in `packages` that:
|
|
121
|
+
* - Are not the root ('')
|
|
122
|
+
* - Don't contain 'node_modules/' (those are installed deps)
|
|
123
|
+
* - Have a version field
|
|
124
|
+
*
|
|
125
|
+
* @param {string | object} input - Lockfile content string or pre-parsed object
|
|
126
|
+
* @returns {string[]} Array of workspace paths (e.g., ['workspaces/arborist', 'workspaces/libnpmfund'])
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* extractWorkspacePaths(lockfile)
|
|
130
|
+
* // => ['workspaces/arborist', 'workspaces/libnpmfund', ...]
|
|
131
|
+
*/
|
|
132
|
+
export function extractWorkspacePaths(input: string | object): string[];
|
|
133
|
+
/**
|
|
134
|
+
* Build workspace packages map by reading package.json files.
|
|
135
|
+
*
|
|
136
|
+
* @param {string | object} input - Lockfile content string or pre-parsed object
|
|
137
|
+
* @param {string} repoDir - Path to repository root
|
|
138
|
+
* @returns {Promise<Record<string, WorkspacePackage>>} Map of workspace path to package info
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* const workspaces = await buildWorkspacePackages(lockfile, '/path/to/repo');
|
|
142
|
+
* // => { 'workspaces/arborist': { name: '@npmcli/arborist', version: '1.0.0', dependencies: {...} } }
|
|
143
|
+
*/
|
|
144
|
+
export function buildWorkspacePackages(input: string | object, repoDir: string): Promise<Record<string, WorkspacePackage>>;
|
|
108
145
|
export type Dependency = import("./types.js").Dependency;
|
|
146
|
+
export type WorkspacePackage = {
|
|
147
|
+
name: string;
|
|
148
|
+
version: string;
|
|
149
|
+
dependencies?: Record<string, string>;
|
|
150
|
+
devDependencies?: Record<string, string>;
|
|
151
|
+
optionalDependencies?: Record<string, string>;
|
|
152
|
+
peerDependencies?: Record<string, string>;
|
|
153
|
+
};
|
|
109
154
|
//# sourceMappingURL=npm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"npm.d.ts","sourceRoot":"","sources":["../../src/parsers/npm.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"npm.d.ts","sourceRoot":"","sources":["../../src/parsers/npm.js"],"names":[],"mappings":"AAGA,4DAA4D;AAE5D;;;;;;;;GAQG;AAEH;;;;;;;;;;;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;AAED;;;;;;;;;;;;;;GAcG;AACH,6CAPW,MAAM,GAAG,MAAM,GACb,MAAM,EAAE,CAsBpB;AAED;;;;;;;;;;GAUG;AACH,8CARW,MAAM,GAAG,MAAM,WACf,MAAM,GACJ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CA6BrD;yBA7Na,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"}
|
|
@@ -115,6 +115,40 @@ export function parseLockfileKey(key: string): string | null;
|
|
|
115
115
|
* const deps = [...fromPnpmLock(lockfile)];
|
|
116
116
|
*/
|
|
117
117
|
export function fromPnpmLock(input: string | object, _options?: Object): Generator<Dependency>;
|
|
118
|
+
/**
|
|
119
|
+
* Extract workspace paths from pnpm lockfile.
|
|
120
|
+
*
|
|
121
|
+
* pnpm stores workspace packages in the `importers` section.
|
|
122
|
+
* Each key is a workspace path relative to the repo root.
|
|
123
|
+
*
|
|
124
|
+
* @param {string | object} input - Lockfile content string or pre-parsed object
|
|
125
|
+
* @returns {string[]} Array of workspace paths (e.g., ['packages/foo', 'packages/bar'])
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* extractWorkspacePaths(lockfile)
|
|
129
|
+
* // => ['packages/vue', 'packages/compiler-core', ...]
|
|
130
|
+
*/
|
|
131
|
+
export function extractWorkspacePaths(input: string | object): string[];
|
|
132
|
+
/**
|
|
133
|
+
* Build workspace packages map by reading package.json files.
|
|
134
|
+
*
|
|
135
|
+
* @param {string | object} input - Lockfile content string or pre-parsed object
|
|
136
|
+
* @param {string} repoDir - Path to repository root
|
|
137
|
+
* @returns {Promise<Record<string, WorkspacePackage>>} Map of workspace path to package info
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* const workspaces = await buildWorkspacePackages(lockfile, '/path/to/repo');
|
|
141
|
+
* // => { 'packages/foo': { name: '@scope/foo', version: '1.0.0', dependencies: {...} } }
|
|
142
|
+
*/
|
|
143
|
+
export function buildWorkspacePackages(input: string | object, repoDir: string): Promise<Record<string, WorkspacePackage>>;
|
|
118
144
|
export { detectVersion } from "./detect.js";
|
|
119
145
|
export type Dependency = import("../types.js").Dependency;
|
|
146
|
+
export type WorkspacePackage = {
|
|
147
|
+
name: string;
|
|
148
|
+
version: string;
|
|
149
|
+
dependencies?: Record<string, string>;
|
|
150
|
+
devDependencies?: Record<string, string>;
|
|
151
|
+
optionalDependencies?: Record<string, string>;
|
|
152
|
+
peerDependencies?: Record<string, string>;
|
|
153
|
+
};
|
|
120
154
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/parsers/pnpm/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/parsers/pnpm/index.js"],"names":[],"mappings":"AAuCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmFG;AACH,gCAzEW,MAAM,GACJ;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CA+H3D;AAED;;;;;;;;;;GAUG;AACH,sCAPW,MAAM,GACJ,MAAM,GAAG,IAAI,CAQzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,oCAbW,MAAM,GAAG,MAAM,aACf,MAAM,GACJ,SAAS,CAAC,UAAU,CAAC,CAoGjC;AAED;;;;;;;;;;;;GAYG;AACH,6CAPW,MAAM,GAAG,MAAM,GACb,MAAM,EAAE,CAapB;AAED;;;;;;;;;;GAUG;AACH,8CARW,MAAM,GAAG,MAAM,WACf,MAAM,GACJ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CA6BrD;;yBAhVa,OAAO,aAAa,EAAE,UAAU;;UAIhC,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"}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
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
|
+
*/
|
|
2
11
|
/**
|
|
3
12
|
* Extract package name from yarn berry resolution field.
|
|
4
13
|
*
|
|
@@ -150,5 +159,39 @@ export function parseLockfileKey(key: string): string;
|
|
|
150
159
|
* @returns {Generator<Dependency>}
|
|
151
160
|
*/
|
|
152
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>>;
|
|
153
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
|
+
};
|
|
154
197
|
//# sourceMappingURL=yarn-berry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yarn-berry.d.ts","sourceRoot":"","sources":["../../src/parsers/yarn-berry.js"],"names":[],"mappings":"
|
|
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"}
|
package/dist/set.d.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*
|
|
17
17
|
* // Get dependencies for a specific workspace
|
|
18
18
|
* const pkg = JSON.parse(await readFile('./packages/foo/package.json'));
|
|
19
|
-
* const subset = set.dependenciesOf(pkg, { workspacePath: 'packages/foo' });
|
|
19
|
+
* const subset = await set.dependenciesOf(pkg, { workspacePath: 'packages/foo', repoDir: '.' });
|
|
20
20
|
*
|
|
21
21
|
* // Set operations
|
|
22
22
|
* const other = await FlatlockSet.fromPath('./other-lock.json');
|
|
@@ -42,27 +42,35 @@ export class FlatlockSet {
|
|
|
42
42
|
* @param {string} content
|
|
43
43
|
* @param {LockfileType} type
|
|
44
44
|
* @param {FromStringOptions} options
|
|
45
|
-
* @returns {{ deps: Map<string, Dependency>, packages: LockfilePackages, importers: LockfileImporters | null }}
|
|
45
|
+
* @returns {{ deps: Map<string, Dependency>, packages: LockfilePackages, importers: LockfileImporters | null, snapshots: Record<string, any> | null }}
|
|
46
46
|
*/
|
|
47
47
|
static "__#private@#parseAll"(content: string, type: LockfileType, options: FromStringOptions): {
|
|
48
48
|
deps: Map<string, Dependency>;
|
|
49
49
|
packages: LockfilePackages;
|
|
50
50
|
importers: LockfileImporters | null;
|
|
51
|
+
snapshots: Record<string, any> | null;
|
|
51
52
|
};
|
|
52
53
|
/**
|
|
53
54
|
* @param {symbol} internal - Must be INTERNAL symbol
|
|
54
55
|
* @param {Map<string, Dependency>} deps
|
|
55
56
|
* @param {LockfilePackages | null} packages
|
|
56
57
|
* @param {LockfileImporters | null} importers
|
|
58
|
+
* @param {Record<string, any> | null} snapshots
|
|
57
59
|
* @param {LockfileType | null} type
|
|
58
60
|
*/
|
|
59
|
-
constructor(internal: symbol, deps: Map<string, Dependency>, packages: LockfilePackages | null, importers: LockfileImporters | null, type: LockfileType | null);
|
|
61
|
+
constructor(internal: symbol, deps: Map<string, Dependency>, packages: LockfilePackages | null, importers: LockfileImporters | null, snapshots: Record<string, any> | null, type: LockfileType | null);
|
|
60
62
|
/** @returns {number} */
|
|
61
63
|
get size(): number;
|
|
62
64
|
/** @returns {LockfileType | null} */
|
|
63
65
|
get type(): LockfileType | null;
|
|
64
66
|
/** @returns {boolean} */
|
|
65
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[];
|
|
66
74
|
/**
|
|
67
75
|
* Check if a dependency exists
|
|
68
76
|
* @param {string} nameAtVersion - e.g., "lodash@4.17.21"
|
|
@@ -126,7 +134,7 @@ export class FlatlockSet {
|
|
|
126
134
|
/**
|
|
127
135
|
* Get transitive dependencies of a package.json
|
|
128
136
|
*
|
|
129
|
-
* For monorepos, provide workspacePath to get correct resolution.
|
|
137
|
+
* For monorepos, provide workspacePath and repoDir to get correct resolution.
|
|
130
138
|
* Without workspacePath, assumes root package (hoisted deps only).
|
|
131
139
|
*
|
|
132
140
|
* NOTE: This method is only available on sets created directly from
|
|
@@ -135,10 +143,17 @@ export class FlatlockSet {
|
|
|
135
143
|
*
|
|
136
144
|
* @param {PackageJson} packageJson - Parsed package.json
|
|
137
145
|
* @param {DependenciesOfOptions} [options]
|
|
138
|
-
* @returns {FlatlockSet}
|
|
146
|
+
* @returns {Promise<FlatlockSet>}
|
|
139
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
|
+
* });
|
|
140
155
|
*/
|
|
141
|
-
dependenciesOf(packageJson: PackageJson, options?: DependenciesOfOptions): FlatlockSet
|
|
156
|
+
dependenciesOf(packageJson: PackageJson, options?: DependenciesOfOptions): Promise<FlatlockSet>;
|
|
142
157
|
/**
|
|
143
158
|
* Convert to array
|
|
144
159
|
* @returns {Dependency[]}
|
|
@@ -150,11 +165,41 @@ export class FlatlockSet {
|
|
|
150
165
|
}
|
|
151
166
|
export type Dependency = import("./parsers/npm.js").Dependency;
|
|
152
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
|
+
};
|
|
153
194
|
export type DependenciesOfOptions = {
|
|
154
195
|
/**
|
|
155
196
|
* - Path to workspace (e.g., 'packages/foo')
|
|
156
197
|
*/
|
|
157
198
|
workspacePath?: string;
|
|
199
|
+
/**
|
|
200
|
+
* - Path to repository root for reading workspace package.json files
|
|
201
|
+
*/
|
|
202
|
+
repoDir?: string;
|
|
158
203
|
/**
|
|
159
204
|
* - Include devDependencies
|
|
160
205
|
*/
|
|
@@ -167,6 +212,10 @@ export type DependenciesOfOptions = {
|
|
|
167
212
|
* - Include peerDependencies (default false: peers are provided by consumer)
|
|
168
213
|
*/
|
|
169
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>;
|
|
170
219
|
};
|
|
171
220
|
export type FromStringOptions = {
|
|
172
221
|
/**
|
package/dist/set.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../src/set.js"],"names":[],"mappings":"
|
|
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
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "The Matlock of lockfile parsers - extracts packages without building dependency graphs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lockfile",
|
|
@@ -35,12 +35,16 @@
|
|
|
35
35
|
},
|
|
36
36
|
"main": "src/index.js",
|
|
37
37
|
"bin": {
|
|
38
|
-
"flatlock
|
|
38
|
+
"flatlock": "bin/flatlock.js",
|
|
39
|
+
"flatlock-cmp": "bin/flatlock-cmp.js",
|
|
40
|
+
"flatcover": "bin/flatcover.js"
|
|
39
41
|
},
|
|
40
42
|
"files": [
|
|
41
43
|
"src",
|
|
42
44
|
"dist",
|
|
43
|
-
"bin"
|
|
45
|
+
"bin/flatlock.js",
|
|
46
|
+
"bin/flatlock-cmp.js",
|
|
47
|
+
"bin/flatcover.js"
|
|
44
48
|
],
|
|
45
49
|
"scripts": {
|
|
46
50
|
"test": "node --test ./test/*.test.js ./test/**/*.test.js",
|
|
@@ -53,29 +57,41 @@
|
|
|
53
57
|
"format:check": "biome format src test",
|
|
54
58
|
"check": "biome check src test && pnpm run build:types",
|
|
55
59
|
"check:fix": "biome check --write src test",
|
|
60
|
+
"build:ncc": "./bin/ncc.sh",
|
|
56
61
|
"prepublishOnly": "pnpm run build:types"
|
|
57
62
|
},
|
|
58
63
|
"dependencies": {
|
|
59
64
|
"@yarnpkg/lockfile": "^1.1.0",
|
|
60
65
|
"@yarnpkg/parsers": "^3.0.3",
|
|
61
|
-
"js-yaml": "^4.1.1"
|
|
66
|
+
"js-yaml": "^4.1.1",
|
|
67
|
+
"undici": "^7.0.0"
|
|
62
68
|
},
|
|
63
69
|
"devDependencies": {
|
|
64
70
|
"@biomejs/biome": "^2.3.8",
|
|
71
|
+
"@vercel/ncc": "^0.38.4",
|
|
65
72
|
"@types/js-yaml": "^4.0.9",
|
|
66
73
|
"@types/node": "^22.10.2",
|
|
67
74
|
"c8": "^10.1.3",
|
|
75
|
+
"chalk": "^5.6.2",
|
|
76
|
+
"fast-glob": "^3.3.3",
|
|
77
|
+
"jackspeak": "^4.1.1",
|
|
68
78
|
"markdownlint-cli2": "^0.17.2",
|
|
69
79
|
"snyk-nodejs-lockfile-parser": "^1.55.0",
|
|
80
|
+
"tinyexec": "^1.0.2",
|
|
70
81
|
"typescript": "^5.7.2"
|
|
71
82
|
},
|
|
72
83
|
"optionalDependencies": {
|
|
73
|
-
"@cyclonedx/
|
|
84
|
+
"@cyclonedx/cdxgen": "^11.3.3",
|
|
74
85
|
"@npmcli/arborist": "^9.1.9",
|
|
75
86
|
"@pnpm/lockfile.fs": "^1001.0.0",
|
|
76
87
|
"@yarnpkg/core": "^4.5.0"
|
|
77
88
|
},
|
|
78
89
|
"packageManager": "pnpm@10.25.0",
|
|
90
|
+
"pnpm": {
|
|
91
|
+
"overrides": {
|
|
92
|
+
"tar": ">=7.5.3"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
79
95
|
"engines": {
|
|
80
96
|
"node": ">=22"
|
|
81
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 {
|
|
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
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
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) {
|
package/src/parsers/index.js
CHANGED
|
@@ -2,9 +2,21 @@
|
|
|
2
2
|
* Re-export all lockfile parsers
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
export { fromPackageLock, parseLockfileKey as parseNpmKey } from './npm.js';
|
|
6
|
-
export { fromPnpmLock, parseLockfileKey as parsePnpmKey } from './pnpm.js';
|
|
7
5
|
export {
|
|
6
|
+
buildWorkspacePackages as buildNpmWorkspacePackages,
|
|
7
|
+
extractWorkspacePaths as extractNpmWorkspacePaths,
|
|
8
|
+
fromPackageLock,
|
|
9
|
+
parseLockfileKey as parseNpmKey
|
|
10
|
+
} from './npm.js';
|
|
11
|
+
export {
|
|
12
|
+
buildWorkspacePackages as buildPnpmWorkspacePackages,
|
|
13
|
+
extractWorkspacePaths as extractPnpmWorkspacePaths,
|
|
14
|
+
fromPnpmLock,
|
|
15
|
+
parseLockfileKey as parsePnpmKey
|
|
16
|
+
} from './pnpm.js';
|
|
17
|
+
export {
|
|
18
|
+
buildWorkspacePackages as buildYarnBerryWorkspacePackages,
|
|
19
|
+
extractWorkspacePaths as extractYarnBerryWorkspacePaths,
|
|
8
20
|
fromYarnBerryLock,
|
|
9
21
|
parseLockfileKey as parseYarnBerryKey,
|
|
10
22
|
parseResolution as parseYarnBerryResolution
|