@pnpm/lockfile.fs 1100.0.8 → 1100.1.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/lib/index.d.ts +2 -1
- package/lib/index.js +1 -0
- package/lib/write.d.ts +25 -3
- package/lib/write.js +47 -8
- package/lib/yamlDocuments.js +5 -1
- package/package.json +9 -9
package/lib/index.d.ts
CHANGED
|
@@ -3,7 +3,8 @@ export { existsNonEmptyWantedLockfile } from './existsWantedLockfile.js';
|
|
|
3
3
|
export { getLockfileImporterId } from './getLockfileImporterId.js';
|
|
4
4
|
export { cleanGitBranchLockfiles } from './gitBranchLockfile.js';
|
|
5
5
|
export { convertToLockfileFile, convertToLockfileObject } from './lockfileFormatConverters.js';
|
|
6
|
+
export { getWantedLockfileName } from './lockfileName.js';
|
|
6
7
|
export * from './read.js';
|
|
7
|
-
export { isEmptyLockfile, writeCurrentLockfile, writeLockfileFile, writeLockfiles, writeWantedLockfile, } from './write.js';
|
|
8
|
+
export { isEmptyLockfile, writeCurrentLockfile, writeLockfileFile, writeLockfiles, type WriteLockfilesResult, writeWantedLockfile, } from './write.js';
|
|
8
9
|
export { extractMainDocument } from './yamlDocuments.js';
|
|
9
10
|
export * from '@pnpm/lockfile.types';
|
package/lib/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export { existsNonEmptyWantedLockfile } from './existsWantedLockfile.js';
|
|
|
3
3
|
export { getLockfileImporterId } from './getLockfileImporterId.js';
|
|
4
4
|
export { cleanGitBranchLockfiles } from './gitBranchLockfile.js';
|
|
5
5
|
export { convertToLockfileFile, convertToLockfileObject } from './lockfileFormatConverters.js';
|
|
6
|
+
export { getWantedLockfileName } from './lockfileName.js';
|
|
6
7
|
export * from './read.js';
|
|
7
8
|
export { isEmptyLockfile, writeCurrentLockfile, writeLockfileFile, writeLockfiles, writeWantedLockfile, } from './write.js';
|
|
8
9
|
export { extractMainDocument } from './yamlDocuments.js';
|
package/lib/write.d.ts
CHANGED
|
@@ -1,12 +1,32 @@
|
|
|
1
1
|
import type { LockfileFile, LockfileObject } from '@pnpm/lockfile.types';
|
|
2
2
|
export declare function lockfileYamlDump(obj: object): string;
|
|
3
|
+
/**
|
|
4
|
+
* Returns the canonical post-write lockfile — structurally identical
|
|
5
|
+
* to what `readWantedLockfile` would parse back. Lets callers like
|
|
6
|
+
* the verification cache hash the as-saved form without re-reading.
|
|
7
|
+
*/
|
|
3
8
|
export declare function writeWantedLockfile(pkgPath: string, wantedLockfile: LockfileObject, opts?: {
|
|
4
9
|
useGitBranchLockfile?: boolean;
|
|
5
10
|
mergeGitBranchLockfiles?: boolean;
|
|
6
|
-
|
|
7
|
-
|
|
11
|
+
/** Pre-resolved filename; skips the `getWantedLockfileName` (and
|
|
12
|
+
* its `getCurrentBranch`) call when supplied. */
|
|
13
|
+
lockfileName?: string;
|
|
14
|
+
}): Promise<LockfileObject>;
|
|
15
|
+
export declare function writeCurrentLockfile(virtualStoreDir: string, currentLockfile: LockfileObject): Promise<LockfileObject | undefined>;
|
|
8
16
|
export declare function writeLockfileFile(lockfilePath: string, wantedLockfile: LockfileFile): Promise<void>;
|
|
9
17
|
export declare function isEmptyLockfile(lockfile: LockfileObject): boolean;
|
|
18
|
+
export interface WriteLockfilesResult {
|
|
19
|
+
/**
|
|
20
|
+
* The canonical "as-saved" wanted lockfile — the inverse converter
|
|
21
|
+
* applied to the same object that was serialized to YAML. Hashing
|
|
22
|
+
* this is equivalent to hashing the lockfile the next install will
|
|
23
|
+
* load from disk (modulo undefined values that YAML drops, which any
|
|
24
|
+
* sensible canonicalization-then-hash routine should strip).
|
|
25
|
+
*/
|
|
26
|
+
wantedLockfile: LockfileObject;
|
|
27
|
+
/** Same as above for the current lockfile, or undefined when it was skipped because empty. */
|
|
28
|
+
currentLockfile: LockfileObject | undefined;
|
|
29
|
+
}
|
|
10
30
|
export declare function writeLockfiles(opts: {
|
|
11
31
|
wantedLockfile: LockfileObject;
|
|
12
32
|
wantedLockfileDir: string;
|
|
@@ -14,4 +34,6 @@ export declare function writeLockfiles(opts: {
|
|
|
14
34
|
currentLockfileDir: string;
|
|
15
35
|
useGitBranchLockfile?: boolean;
|
|
16
36
|
mergeGitBranchLockfiles?: boolean;
|
|
17
|
-
}
|
|
37
|
+
/** See {@link writeWantedLockfile}'s `lockfileName` option. */
|
|
38
|
+
wantedLockfileName?: string;
|
|
39
|
+
}): Promise<WriteLockfilesResult>;
|
package/lib/write.js
CHANGED
|
@@ -5,7 +5,7 @@ import { rimraf } from '@zkochan/rimraf';
|
|
|
5
5
|
import yaml from 'js-yaml';
|
|
6
6
|
import { isEmpty } from 'ramda';
|
|
7
7
|
import writeFileAtomic from 'write-file-atomic';
|
|
8
|
-
import { convertToLockfileFile } from './lockfileFormatConverters.js';
|
|
8
|
+
import { convertToLockfileFile, convertToLockfileObject } from './lockfileFormatConverters.js';
|
|
9
9
|
import { getWantedLockfileName } from './lockfileName.js';
|
|
10
10
|
import { lockfileLogger as logger } from './logger.js';
|
|
11
11
|
import { sortLockfileKeys } from './sortLockfileKeys.js';
|
|
@@ -20,15 +20,20 @@ const LOCKFILE_YAML_FORMAT = {
|
|
|
20
20
|
export function lockfileYamlDump(obj) {
|
|
21
21
|
return yaml.dump(obj, LOCKFILE_YAML_FORMAT);
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Returns the canonical post-write lockfile — structurally identical
|
|
25
|
+
* to what `readWantedLockfile` would parse back. Lets callers like
|
|
26
|
+
* the verification cache hash the as-saved form without re-reading.
|
|
27
|
+
*/
|
|
23
28
|
export async function writeWantedLockfile(pkgPath, wantedLockfile, opts) {
|
|
24
|
-
const wantedLockfileName = await getWantedLockfileName(opts);
|
|
29
|
+
const wantedLockfileName = opts?.lockfileName ?? await getWantedLockfileName(opts);
|
|
25
30
|
return writeLockfile(wantedLockfileName, pkgPath, wantedLockfile);
|
|
26
31
|
}
|
|
27
32
|
export async function writeCurrentLockfile(virtualStoreDir, currentLockfile) {
|
|
28
33
|
// empty lockfile is not saved
|
|
29
34
|
if (isEmptyLockfile(currentLockfile)) {
|
|
30
35
|
await rimraf(path.join(virtualStoreDir, 'lock.yaml'));
|
|
31
|
-
return;
|
|
36
|
+
return undefined;
|
|
32
37
|
}
|
|
33
38
|
await fs.mkdir(virtualStoreDir, { recursive: true });
|
|
34
39
|
return writeLockfile('lock.yaml', virtualStoreDir, currentLockfile);
|
|
@@ -45,9 +50,29 @@ async function writeLockfile(lockfileFilename, pkgPath, wantedLockfile) {
|
|
|
45
50
|
// in the OS page cache and streaming stops at the first separator.
|
|
46
51
|
const envDoc = await streamReadFirstYamlDocument(lockfilePath);
|
|
47
52
|
const envPrefix = envDoc != null ? `${YAML_DOCUMENT_START}${envDoc}${YAML_DOCUMENT_SEPARATOR}` : '';
|
|
48
|
-
|
|
53
|
+
await writeFileAtomic(lockfilePath, `${envPrefix}${yamlDoc}`);
|
|
49
54
|
}
|
|
50
|
-
|
|
55
|
+
else {
|
|
56
|
+
await writeFileAtomic(lockfilePath, yamlDoc);
|
|
57
|
+
}
|
|
58
|
+
// YAML drops undefined on serialize, so the in-memory LockfileFile
|
|
59
|
+
// can carry fields (like an unset settings.dedupePeers) that won't
|
|
60
|
+
// survive a round-trip; strip them to mirror what the next reader
|
|
61
|
+
// will parse back.
|
|
62
|
+
return convertToLockfileObject(stripUndefinedDeep(lockfileToStringify));
|
|
63
|
+
}
|
|
64
|
+
function stripUndefinedDeep(value) {
|
|
65
|
+
if (value === null || typeof value !== 'object')
|
|
66
|
+
return value;
|
|
67
|
+
if (Array.isArray(value))
|
|
68
|
+
return value.map(stripUndefinedDeep);
|
|
69
|
+
const out = {};
|
|
70
|
+
for (const [k, v] of Object.entries(value)) {
|
|
71
|
+
if (v === undefined)
|
|
72
|
+
continue;
|
|
73
|
+
out[k] = stripUndefinedDeep(v);
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
51
76
|
}
|
|
52
77
|
export function writeLockfileFile(lockfilePath, wantedLockfile) {
|
|
53
78
|
const yamlDoc = yamlStringify(wantedLockfile);
|
|
@@ -61,7 +86,7 @@ export function isEmptyLockfile(lockfile) {
|
|
|
61
86
|
return Object.values(lockfile.importers).every((importer) => isEmpty(importer.specifiers ?? {}) && isEmpty(importer.dependencies ?? {}));
|
|
62
87
|
}
|
|
63
88
|
export async function writeLockfiles(opts) {
|
|
64
|
-
const wantedLockfileName = await getWantedLockfileName(opts);
|
|
89
|
+
const wantedLockfileName = opts.wantedLockfileName ?? await getWantedLockfileName(opts);
|
|
65
90
|
const wantedLockfilePath = path.join(opts.wantedLockfileDir, wantedLockfileName);
|
|
66
91
|
const currentLockfilePath = path.join(opts.currentLockfileDir, 'lock.yaml');
|
|
67
92
|
const wantedLockfileToStringify = convertToLockfileFile(opts.wantedLockfile);
|
|
@@ -92,7 +117,12 @@ export async function writeLockfiles(opts) {
|
|
|
92
117
|
}
|
|
93
118
|
})(),
|
|
94
119
|
]);
|
|
95
|
-
|
|
120
|
+
// Both files share the same source object; strip once and reuse.
|
|
121
|
+
const normalized = convertToLockfileObject(stripUndefinedDeep(wantedLockfileToStringify));
|
|
122
|
+
return {
|
|
123
|
+
wantedLockfile: normalized,
|
|
124
|
+
currentLockfile: isEmptyLockfile(opts.wantedLockfile) ? undefined : normalized,
|
|
125
|
+
};
|
|
96
126
|
}
|
|
97
127
|
logger.debug({
|
|
98
128
|
message: `\`${WANTED_LOCKFILE}\` differs from \`${path.relative(opts.wantedLockfileDir, currentLockfilePath)}\``,
|
|
@@ -100,10 +130,13 @@ export async function writeLockfiles(opts) {
|
|
|
100
130
|
});
|
|
101
131
|
const currentLockfileToStringify = convertToLockfileFile(opts.currentLockfile);
|
|
102
132
|
const currentYamlDoc = yamlStringify(currentLockfileToStringify);
|
|
133
|
+
// Filtered-current callers (deps-restorer) can pass an empty
|
|
134
|
+
// current against a non-empty wanted; key off the current.
|
|
135
|
+
const currentIsEmpty = isEmptyLockfile(opts.currentLockfile);
|
|
103
136
|
await Promise.all([
|
|
104
137
|
writeFileAtomic(wantedLockfilePath, wantedYamlDoc),
|
|
105
138
|
(async () => {
|
|
106
|
-
if (
|
|
139
|
+
if (currentIsEmpty) {
|
|
107
140
|
await rimraf(currentLockfilePath);
|
|
108
141
|
}
|
|
109
142
|
else {
|
|
@@ -112,5 +145,11 @@ export async function writeLockfiles(opts) {
|
|
|
112
145
|
}
|
|
113
146
|
})(),
|
|
114
147
|
]);
|
|
148
|
+
return {
|
|
149
|
+
wantedLockfile: convertToLockfileObject(stripUndefinedDeep(wantedLockfileToStringify)),
|
|
150
|
+
currentLockfile: currentIsEmpty
|
|
151
|
+
? undefined
|
|
152
|
+
: convertToLockfileObject(stripUndefinedDeep(currentLockfileToStringify)),
|
|
153
|
+
};
|
|
115
154
|
}
|
|
116
155
|
//# sourceMappingURL=write.js.map
|
package/lib/yamlDocuments.js
CHANGED
|
@@ -24,6 +24,8 @@ export async function streamReadFirstYamlDocument(filePath) {
|
|
|
24
24
|
else {
|
|
25
25
|
buffer += chunk.value;
|
|
26
26
|
}
|
|
27
|
+
// Normalize CRLF (Windows) to LF so document separator detection works.
|
|
28
|
+
buffer = buffer.replace(/\r\n/g, '\n');
|
|
27
29
|
if (buffer.length >= YAML_DOCUMENT_START.length)
|
|
28
30
|
break;
|
|
29
31
|
}
|
|
@@ -41,7 +43,8 @@ export async function streamReadFirstYamlDocument(filePath) {
|
|
|
41
43
|
const chunk = await chunks.next(); // eslint-disable-line no-await-in-loop
|
|
42
44
|
if (chunk.done)
|
|
43
45
|
break;
|
|
44
|
-
|
|
46
|
+
// Normalize CRLF (Windows) to LF so the separator search matches on Windows-checked-out files.
|
|
47
|
+
buffer = (buffer + chunk.value).replace(/\r\n/g, '\n');
|
|
45
48
|
}
|
|
46
49
|
}
|
|
47
50
|
catch (err) {
|
|
@@ -60,6 +63,7 @@ export async function streamReadFirstYamlDocument(filePath) {
|
|
|
60
63
|
* Otherwise returns the entire content (no env document present).
|
|
61
64
|
*/
|
|
62
65
|
export function extractMainDocument(content) {
|
|
66
|
+
content = content.replace(/\r\n/g, '\n');
|
|
63
67
|
if (!content.startsWith(YAML_DOCUMENT_START))
|
|
64
68
|
return content;
|
|
65
69
|
const sep = content.indexOf(YAML_DOCUMENT_SEPARATOR, YAML_DOCUMENT_START.length);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/lockfile.fs",
|
|
3
|
-
"version": "1100.0
|
|
3
|
+
"version": "1100.1.0",
|
|
4
4
|
"description": "Read/write pnpm-lock.yaml files",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -34,15 +34,15 @@
|
|
|
34
34
|
"semver": "^7.7.2",
|
|
35
35
|
"strip-bom": "^5.0.0",
|
|
36
36
|
"write-file-atomic": "^7.0.0",
|
|
37
|
-
"@pnpm/constants": "1100.0.0",
|
|
38
37
|
"@pnpm/deps.path": "1100.0.3",
|
|
39
|
-
"@pnpm/
|
|
40
|
-
"@pnpm/lockfile.merger": "1100.0.
|
|
41
|
-
"@pnpm/
|
|
42
|
-
"@pnpm/lockfile.utils": "1100.0.7",
|
|
38
|
+
"@pnpm/constants": "1100.0.0",
|
|
39
|
+
"@pnpm/lockfile.merger": "1100.0.6",
|
|
40
|
+
"@pnpm/object.key-sorting": "1100.0.0",
|
|
43
41
|
"@pnpm/network.git-utils": "1100.0.1",
|
|
42
|
+
"@pnpm/lockfile.utils": "1100.0.8",
|
|
44
43
|
"@pnpm/types": "1101.1.0",
|
|
45
|
-
"@pnpm/
|
|
44
|
+
"@pnpm/lockfile.types": "1100.0.6",
|
|
45
|
+
"@pnpm/error": "1100.0.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@pnpm/logger": ">=1001.0.0 <1002.0.0"
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
"tempy": "3.0.0",
|
|
58
58
|
"write-yaml-file": "^6.0.0",
|
|
59
59
|
"yaml-tag": "1.1.0",
|
|
60
|
-
"@pnpm/
|
|
61
|
-
"@pnpm/
|
|
60
|
+
"@pnpm/logger": "1100.0.0",
|
|
61
|
+
"@pnpm/lockfile.fs": "1100.1.0"
|
|
62
62
|
},
|
|
63
63
|
"engines": {
|
|
64
64
|
"node": ">=22.13"
|