flatlock 1.5.0 → 1.5.1
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/dist/detect.d.ts.map +1 -1
- package/dist/parsers/index.d.ts +1 -1
- package/dist/parsers/pnpm/index.d.ts +11 -0
- package/dist/parsers/pnpm/index.d.ts.map +1 -1
- package/package.json +6 -3
- package/src/detect.js +16 -6
- package/src/parsers/index.js +2 -1
- package/src/parsers/pnpm/index.js +33 -3
- package/src/set.js +2 -2
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":"AAuGA;;;;;;;;;;;;;;GAcG;AACH,+CALG;IAAyB,IAAI;IACJ,OAAO;CAChC,GAAU,YAAY,CAgDxB;AA/JD;;GAEG;AAEH;;GAEG;AACH;;;;;GAKG;2BAXU,KAAK,GAAG,MAAM,GAAG,cAAc,GAAG,YAAY"}
|
package/dist/parsers/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
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";
|
|
2
|
+
export { buildWorkspacePackages as buildPnpmWorkspacePackages, extractWorkspacePaths as extractPnpmWorkspacePaths, fromPnpmLock, parseLockfileKey as parsePnpmKey, parsePnpmYaml } from "./pnpm.js";
|
|
3
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
|
|
@@ -98,6 +98,17 @@ export function parseSpec(spec: string): {
|
|
|
98
98
|
* parseLockfileKey('/lodash/4.17.21') // => 'lodash'
|
|
99
99
|
*/
|
|
100
100
|
export function parseLockfileKey(key: string): string | null;
|
|
101
|
+
/**
|
|
102
|
+
* Parse pnpm YAML content, tolerating truncated files.
|
|
103
|
+
*
|
|
104
|
+
* pnpm lockfiles use inline flow collections like `{integrity: sha512-...}`
|
|
105
|
+
* which cause js-yaml to throw if the file is truncated mid-entry. When that
|
|
106
|
+
* happens, we progressively trim trailing lines until parsing succeeds.
|
|
107
|
+
*
|
|
108
|
+
* @param {string} content - YAML content
|
|
109
|
+
* @returns {Record<string, any>} Parsed lockfile object
|
|
110
|
+
*/
|
|
111
|
+
export function parsePnpmYaml(content: string): Record<string, any>;
|
|
101
112
|
/**
|
|
102
113
|
* Parse pnpm lockfile (shrinkwrap.yaml, pnpm-lock.yaml v5.x, v6, v9)
|
|
103
114
|
*
|
|
@@ -1 +1 @@
|
|
|
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;;
|
|
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;;;;;;;;;GASG;AACH,uCAHW,MAAM,GACJ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAoB/B;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;;yBA9Wa,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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flatlock",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "The Matlock of lockfile parsers - extracts packages without building dependency graphs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lockfile",
|
|
@@ -47,8 +47,11 @@
|
|
|
47
47
|
"bin/flatcover.js"
|
|
48
48
|
],
|
|
49
49
|
"scripts": {
|
|
50
|
-
"
|
|
51
|
-
"
|
|
50
|
+
"pretest": "node test/fixtures/decode.js",
|
|
51
|
+
"pretest:coverage": "node test/fixtures/decode.js",
|
|
52
|
+
"test": "node --test ./test/*.test.js ./test/parsers/*.test.js",
|
|
53
|
+
"test:coverage": "c8 node --test ./test/*.test.js ./test/parsers/*.test.js",
|
|
54
|
+
"test:all": "node --test ./test/*.test.js ./test/**/*.test.js",
|
|
52
55
|
"build:types": "tsc",
|
|
53
56
|
"lint": "biome lint src test",
|
|
54
57
|
"lint:fix": "biome lint --write src test",
|
package/src/detect.js
CHANGED
|
@@ -61,25 +61,35 @@ function tryParseYarnClassic(content) {
|
|
|
61
61
|
|
|
62
62
|
const result = parseYarnClassic(content);
|
|
63
63
|
// Must parse successfully and NOT have __metadata (that's berry)
|
|
64
|
-
// Must have at least one package entry (not empty object)
|
|
65
64
|
const isValidResult = result.type === 'success' || result.type === 'merge';
|
|
66
|
-
const
|
|
67
|
-
const notBerry = !('__metadata' in result.object);
|
|
65
|
+
const hasObject = result.object && typeof result.object === 'object';
|
|
66
|
+
const notBerry = hasObject && !('__metadata' in result.object);
|
|
67
|
+
// Must have entries OR start with the yarn lockfile header comment
|
|
68
|
+
const hasEntries = hasObject && Object.keys(result.object).length > 0;
|
|
69
|
+
const firstLines = content.split('\n', 5).join('\n');
|
|
70
|
+
const hasYarnHeader = /^# yarn lockfile v1/m.test(firstLines);
|
|
68
71
|
|
|
69
|
-
return isValidResult &&
|
|
72
|
+
return isValidResult && hasObject && notBerry && (hasEntries || hasYarnHeader);
|
|
70
73
|
} catch {
|
|
71
74
|
return false;
|
|
72
75
|
}
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
/**
|
|
76
|
-
* Try to parse content as pnpm lockfile
|
|
79
|
+
* Try to parse content as pnpm lockfile.
|
|
80
|
+
*
|
|
81
|
+
* Only parses the YAML header (first 20 lines) to check for lockfileVersion.
|
|
82
|
+
* This avoids failures on truncated lockfiles where the body is incomplete
|
|
83
|
+
* but the header is valid.
|
|
84
|
+
*
|
|
77
85
|
* @param {string} content
|
|
78
86
|
* @returns {boolean}
|
|
79
87
|
*/
|
|
80
88
|
function tryParsePnpm(content) {
|
|
81
89
|
try {
|
|
82
|
-
|
|
90
|
+
// Parse only the header to tolerate truncated lockfiles
|
|
91
|
+
const header = content.split('\n', 20).join('\n');
|
|
92
|
+
const parsed = yaml.load(header);
|
|
83
93
|
// Must have lockfileVersion at root and NOT have __metadata
|
|
84
94
|
// biome-ignore format: preserve multiline logical expression
|
|
85
95
|
return !!(parsed
|
package/src/parsers/index.js
CHANGED
|
@@ -12,7 +12,8 @@ export {
|
|
|
12
12
|
buildWorkspacePackages as buildPnpmWorkspacePackages,
|
|
13
13
|
extractWorkspacePaths as extractPnpmWorkspacePaths,
|
|
14
14
|
fromPnpmLock,
|
|
15
|
-
parseLockfileKey as parsePnpmKey
|
|
15
|
+
parseLockfileKey as parsePnpmKey,
|
|
16
|
+
parsePnpmYaml
|
|
16
17
|
} from './pnpm.js';
|
|
17
18
|
export {
|
|
18
19
|
buildWorkspacePackages as buildYarnBerryWorkspacePackages,
|
|
@@ -193,6 +193,36 @@ export function parseLockfileKey(key) {
|
|
|
193
193
|
return parseSpec(key).name;
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Parse pnpm YAML content, tolerating truncated files.
|
|
198
|
+
*
|
|
199
|
+
* pnpm lockfiles use inline flow collections like `{integrity: sha512-...}`
|
|
200
|
+
* which cause js-yaml to throw if the file is truncated mid-entry. When that
|
|
201
|
+
* happens, we progressively trim trailing lines until parsing succeeds.
|
|
202
|
+
*
|
|
203
|
+
* @param {string} content - YAML content
|
|
204
|
+
* @returns {Record<string, any>} Parsed lockfile object
|
|
205
|
+
*/
|
|
206
|
+
export function parsePnpmYaml(content) {
|
|
207
|
+
try {
|
|
208
|
+
return /** @type {Record<string, any>} */ (yaml.load(content));
|
|
209
|
+
} catch {
|
|
210
|
+
// Truncated file — trim lines from the end until yaml.load succeeds.
|
|
211
|
+
// Most truncations break an incomplete flow collection near the end,
|
|
212
|
+
// so we only need to trim a handful of lines.
|
|
213
|
+
const lines = content.split('\n');
|
|
214
|
+
for (let trim = 1; trim < Math.min(20, lines.length); trim++) {
|
|
215
|
+
try {
|
|
216
|
+
return /** @type {Record<string, any>} */ (yaml.load(lines.slice(0, -trim).join('\n')));
|
|
217
|
+
} catch {
|
|
218
|
+
// keep trimming
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// If trimming didn't help, re-throw the original error
|
|
222
|
+
throw yaml.load(content);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
196
226
|
/**
|
|
197
227
|
* Parse pnpm lockfile (shrinkwrap.yaml, pnpm-lock.yaml v5.x, v6, v9)
|
|
198
228
|
*
|
|
@@ -211,7 +241,7 @@ export function parseLockfileKey(key) {
|
|
|
211
241
|
*/
|
|
212
242
|
export function* fromPnpmLock(input, _options = {}) {
|
|
213
243
|
const lockfile = /** @type {Record<string, any>} */ (
|
|
214
|
-
typeof input === 'string' ?
|
|
244
|
+
typeof input === 'string' ? parsePnpmYaml(input) : input
|
|
215
245
|
);
|
|
216
246
|
|
|
217
247
|
// Detect version to determine where to look for packages
|
|
@@ -250,7 +280,7 @@ export function* fromPnpmLock(input, _options = {}) {
|
|
|
250
280
|
if (seen.has(key)) continue;
|
|
251
281
|
seen.add(key);
|
|
252
282
|
|
|
253
|
-
const resolution = pkg
|
|
283
|
+
const resolution = pkg?.resolution || {};
|
|
254
284
|
const integrity = resolution.integrity;
|
|
255
285
|
const resolved = resolution.tarball;
|
|
256
286
|
const link = spec.startsWith('link:') || resolution.type === 'directory';
|
|
@@ -315,7 +345,7 @@ export function* fromPnpmLock(input, _options = {}) {
|
|
|
315
345
|
*/
|
|
316
346
|
export function extractWorkspacePaths(input) {
|
|
317
347
|
const lockfile = /** @type {Record<string, any>} */ (
|
|
318
|
-
typeof input === 'string' ?
|
|
348
|
+
typeof input === 'string' ? parsePnpmYaml(input) : input
|
|
319
349
|
);
|
|
320
350
|
|
|
321
351
|
const importers = lockfile.importers || {};
|
package/src/set.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { parseSyml } from '@yarnpkg/parsers';
|
|
3
|
-
import yaml from 'js-yaml';
|
|
4
3
|
import { detectType, Type } from './detect.js';
|
|
5
4
|
import {
|
|
6
5
|
buildNpmWorkspacePackages,
|
|
@@ -13,6 +12,7 @@ import {
|
|
|
13
12
|
fromPnpmLock,
|
|
14
13
|
fromYarnBerryLock,
|
|
15
14
|
fromYarnClassicLock,
|
|
15
|
+
parsePnpmYaml,
|
|
16
16
|
parseYarnBerryKey,
|
|
17
17
|
parseYarnClassic,
|
|
18
18
|
parseYarnClassicKey
|
|
@@ -195,7 +195,7 @@ export class FlatlockSet {
|
|
|
195
195
|
}
|
|
196
196
|
case Type.PNPM: {
|
|
197
197
|
/** @type {any} */
|
|
198
|
-
const lockfile =
|
|
198
|
+
const lockfile = parsePnpmYaml(content);
|
|
199
199
|
packages = lockfile.packages || {};
|
|
200
200
|
importers = lockfile.importers || null;
|
|
201
201
|
snapshots = lockfile.snapshots || null;
|