@pnpm/lockfile.fs 1100.1.13 → 1100.1.14
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/CHANGELOG.md +17 -0
- package/lib/envLockfile.d.ts +4 -0
- package/lib/envLockfile.js +61 -0
- package/lib/errors/LockfileBreakingChangeError.d.ts +5 -0
- package/lib/errors/LockfileBreakingChangeError.js +9 -0
- package/lib/errors/index.d.ts +1 -0
- package/lib/errors/index.js +2 -0
- package/lib/existsWantedLockfile.d.ts +6 -0
- package/lib/existsWantedLockfile.js +23 -0
- package/lib/getLockfileImporterId.d.ts +2 -0
- package/lib/getLockfileImporterId.js +6 -0
- package/lib/gitBranchLockfile.d.ts +3 -0
- package/lib/gitBranchLockfile.js +22 -0
- package/lib/gitMergeFile.d.ts +3 -0
- package/lib/gitMergeFile.js +47 -0
- package/lib/index.d.ts +10 -0
- package/lib/lockfileFormatConverters.d.ts +3 -0
- package/lib/lockfileFormatConverters.js +227 -0
- package/lib/lockfileName.d.ts +6 -0
- package/lib/lockfileName.js +19 -0
- package/lib/logger.d.ts +1 -0
- package/lib/logger.js +3 -0
- package/lib/read.d.ts +42 -0
- package/lib/read.js +203 -0
- package/lib/sortLockfileKeys.d.ts +3 -0
- package/lib/sortLockfileKeys.js +78 -0
- package/lib/write.d.ts +39 -0
- package/lib/write.js +203 -0
- package/lib/yamlDocuments.d.ts +27 -0
- package/lib/yamlDocuments.js +165 -0
- package/package.json +11 -11
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { constants } from 'node:fs';
|
|
2
|
+
import { lstat, open, readFile } from 'node:fs/promises';
|
|
3
|
+
import { StringDecoder } from 'node:string_decoder';
|
|
4
|
+
import util from 'node:util';
|
|
5
|
+
import { PnpmError } from '@pnpm/error';
|
|
6
|
+
import stripBom from 'strip-bom';
|
|
7
|
+
export const YAML_DOCUMENT_SEPARATOR = '\n---\n';
|
|
8
|
+
export const YAML_DOCUMENT_START = '---\n';
|
|
9
|
+
const READ_BUFFER_SIZE = 64 * 1024;
|
|
10
|
+
const LOCKFILE_READ_FLAGS = constants.O_RDONLY | (process.platform === 'win32' ? 0 : constants.O_NOFOLLOW);
|
|
11
|
+
/**
|
|
12
|
+
* Reads the first YAML document from a multi-document YAML file using streaming.
|
|
13
|
+
* The file must start with "---\n" to indicate it contains an env lockfile document.
|
|
14
|
+
* Stops reading as soon as the second document separator is found.
|
|
15
|
+
* Returns null if the file doesn't exist or doesn't start with "---\n".
|
|
16
|
+
*/
|
|
17
|
+
export async function streamReadFirstYamlDocument(filePath, readBufferSize = READ_BUFFER_SIZE) {
|
|
18
|
+
let fileHandle;
|
|
19
|
+
let buffer = '';
|
|
20
|
+
let firstChunk = true;
|
|
21
|
+
try {
|
|
22
|
+
fileHandle = await open(filePath, constants.O_RDONLY);
|
|
23
|
+
const decoder = new StringDecoder('utf8');
|
|
24
|
+
const readBuffer = Buffer.allocUnsafe(normalizeReadBufferSize(readBufferSize));
|
|
25
|
+
let position = 0;
|
|
26
|
+
while (true) {
|
|
27
|
+
const { bytesRead } = await fileHandle.read(readBuffer, 0, readBuffer.length, position); // eslint-disable-line no-await-in-loop
|
|
28
|
+
if (bytesRead === 0)
|
|
29
|
+
break;
|
|
30
|
+
position += bytesRead;
|
|
31
|
+
let chunk = decoder.write(readBuffer.subarray(0, bytesRead));
|
|
32
|
+
if (firstChunk && chunk.length > 0) {
|
|
33
|
+
// Strip BOM from the first chunk. Safe because the decoder uses utf8,
|
|
34
|
+
// so the 3-byte BOM is decoded into a single \uFEFF character.
|
|
35
|
+
chunk = stripBom(chunk);
|
|
36
|
+
firstChunk = false;
|
|
37
|
+
}
|
|
38
|
+
buffer += chunk;
|
|
39
|
+
// Normalize CRLF (Windows) to LF so document separator detection works.
|
|
40
|
+
buffer = buffer.replace(/\r\n/g, '\n');
|
|
41
|
+
if (canRejectDocumentStart(buffer)) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
const sep = buffer.indexOf(YAML_DOCUMENT_SEPARATOR, YAML_DOCUMENT_START.length);
|
|
45
|
+
if (sep !== -1) {
|
|
46
|
+
return buffer.slice(YAML_DOCUMENT_START.length, sep);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const remainder = decoder.end();
|
|
50
|
+
if (remainder.length > 0) {
|
|
51
|
+
buffer += firstChunk ? stripBom(remainder) : remainder;
|
|
52
|
+
buffer = buffer.replace(/\r\n/g, '\n');
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
if (util.types.isNativeError(err) && 'code' in err && err.code === 'ENOENT') {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
await fileHandle?.close().catch(() => { });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export async function readLockfileToString(filePath) {
|
|
67
|
+
try {
|
|
68
|
+
return stripBom(await readFile(filePath, 'utf8')).replace(/\r\n/g, '\n');
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
if (util.types.isNativeError(err) && 'code' in err && err.code === 'ENOENT') {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
throw err;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export async function readLockfileToStringNoFollow(filePath) {
|
|
78
|
+
let fileHandle;
|
|
79
|
+
try {
|
|
80
|
+
fileHandle = await openLockfileNoFollow(filePath);
|
|
81
|
+
return await fileHandle.readFile('utf8');
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
if (util.types.isNativeError(err) && 'code' in err && err.code === 'ENOENT') {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
throw err;
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
await fileHandle?.close().catch(() => { });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async function openLockfileNoFollow(filePath) {
|
|
94
|
+
await ensureLockfileIsNotSymlink(filePath);
|
|
95
|
+
try {
|
|
96
|
+
return await open(filePath, LOCKFILE_READ_FLAGS);
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
if (util.types.isNativeError(err) && 'code' in err && err.code === 'ELOOP') {
|
|
100
|
+
throw symlinkedLockfileError(filePath);
|
|
101
|
+
}
|
|
102
|
+
throw err;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Refuses a symlinked lockfile before a write, which would land on the link's
|
|
107
|
+
* target — any file the user can write. Reads may follow it: sandboxes stage
|
|
108
|
+
* `pnpm-lock.yaml` as a symlink, and lockfile content is untrusted either way
|
|
109
|
+
* (https://github.com/pnpm/pnpm/issues/13073).
|
|
110
|
+
*/
|
|
111
|
+
export async function ensureLockfileIsNotSymlink(filePath) {
|
|
112
|
+
let stat;
|
|
113
|
+
try {
|
|
114
|
+
stat = await lstat(filePath);
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
if (util.types.isNativeError(err) && 'code' in err && err.code === 'ENOENT') {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
throw err;
|
|
121
|
+
}
|
|
122
|
+
if (stat.isSymbolicLink()) {
|
|
123
|
+
throw symlinkedLockfileError(filePath);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function symlinkedLockfileError(filePath) {
|
|
127
|
+
return new PnpmError('LOCKFILE_IS_SYMLINK', `Refusing to write symlinked lockfile at ${filePath}`);
|
|
128
|
+
}
|
|
129
|
+
function canRejectDocumentStart(buffer) {
|
|
130
|
+
if (buffer.length < YAML_DOCUMENT_START.length)
|
|
131
|
+
return false;
|
|
132
|
+
if (buffer === '---\r')
|
|
133
|
+
return false;
|
|
134
|
+
return !buffer.startsWith(YAML_DOCUMENT_START);
|
|
135
|
+
}
|
|
136
|
+
function normalizeReadBufferSize(readBufferSize) {
|
|
137
|
+
const size = Number.isFinite(readBufferSize) ? Math.floor(readBufferSize) : READ_BUFFER_SIZE;
|
|
138
|
+
return size > 0 ? size : READ_BUFFER_SIZE;
|
|
139
|
+
}
|
|
140
|
+
/** The in-memory counterpart of {@link streamReadFirstYamlDocument}. */
|
|
141
|
+
export function extractEnvDocument(content) {
|
|
142
|
+
content = content.replace(/\r\n/g, '\n');
|
|
143
|
+
if (!content.startsWith(YAML_DOCUMENT_START))
|
|
144
|
+
return null;
|
|
145
|
+
const sep = content.indexOf(YAML_DOCUMENT_SEPARATOR, YAML_DOCUMENT_START.length);
|
|
146
|
+
if (sep === -1)
|
|
147
|
+
return null;
|
|
148
|
+
return content.slice(YAML_DOCUMENT_START.length, sep);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Extracts the main lockfile content (second YAML document) from a combined string.
|
|
152
|
+
* If the file starts with "---\n", returns the content after the separator.
|
|
153
|
+
* If there is no separator, returns empty string (file is env-only).
|
|
154
|
+
* Otherwise returns the entire content (no env document present).
|
|
155
|
+
*/
|
|
156
|
+
export function extractMainDocument(content) {
|
|
157
|
+
content = content.replace(/\r\n/g, '\n');
|
|
158
|
+
if (!content.startsWith(YAML_DOCUMENT_START))
|
|
159
|
+
return content;
|
|
160
|
+
const sep = content.indexOf(YAML_DOCUMENT_SEPARATOR, YAML_DOCUMENT_START.length);
|
|
161
|
+
if (sep === -1)
|
|
162
|
+
return '';
|
|
163
|
+
return content.slice(sep + YAML_DOCUMENT_SEPARATOR.length);
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=yamlDocuments.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/lockfile.fs",
|
|
3
|
-
"version": "1100.1.
|
|
3
|
+
"version": "1100.1.14",
|
|
4
4
|
"description": "Read/write pnpm-lock.yaml files",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -29,15 +29,15 @@
|
|
|
29
29
|
"!*.map"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@pnpm/constants": "1100.0.
|
|
33
|
-
"@pnpm/deps.path": "1100.0.
|
|
34
|
-
"@pnpm/error": "1100.0
|
|
35
|
-
"@pnpm/lockfile.merger": "1100.0.
|
|
36
|
-
"@pnpm/lockfile.types": "1100.0.
|
|
37
|
-
"@pnpm/lockfile.utils": "1100.1.
|
|
38
|
-
"@pnpm/network.git-utils": "1100.0.
|
|
39
|
-
"@pnpm/object.key-sorting": "1100.0.
|
|
40
|
-
"@pnpm/types": "1101.
|
|
32
|
+
"@pnpm/constants": "1100.0.1",
|
|
33
|
+
"@pnpm/deps.path": "1100.0.11",
|
|
34
|
+
"@pnpm/error": "1100.1.0",
|
|
35
|
+
"@pnpm/lockfile.merger": "1100.0.16",
|
|
36
|
+
"@pnpm/lockfile.types": "1100.0.16",
|
|
37
|
+
"@pnpm/lockfile.utils": "1100.1.5",
|
|
38
|
+
"@pnpm/network.git-utils": "1100.0.3",
|
|
39
|
+
"@pnpm/object.key-sorting": "1100.0.2",
|
|
40
|
+
"@pnpm/types": "1101.6.0",
|
|
41
41
|
"@zkochan/rimraf": "^4.0.0",
|
|
42
42
|
"comver-to-semver": "^2.0.0",
|
|
43
43
|
"js-yaml": "npm:@zkochan/js-yaml@0.0.11",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@jest/globals": "30.4.1",
|
|
55
|
-
"@pnpm/lockfile.fs": "1100.1.
|
|
55
|
+
"@pnpm/lockfile.fs": "1100.1.14",
|
|
56
56
|
"@pnpm/logger": "1100.0.0",
|
|
57
57
|
"@types/js-yaml": "^4.0.9",
|
|
58
58
|
"@types/normalize-path": "^3.0.2",
|