@pnpm/lockfile.fs 1001.1.31 → 1100.0.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/envLockfile.d.ts +4 -0
- package/lib/envLockfile.js +72 -0
- package/lib/errors/LockfileBreakingChangeError.js +2 -6
- package/lib/errors/index.js +1 -5
- package/lib/existsWantedLockfile.d.ts +2 -2
- package/lib/existsWantedLockfile.js +6 -12
- package/lib/getLockfileImporterId.d.ts +1 -1
- package/lib/getLockfileImporterId.js +4 -10
- package/lib/gitBranchLockfile.js +8 -15
- package/lib/gitMergeFile.d.ts +1 -1
- package/lib/gitMergeFile.js +6 -13
- package/lib/index.d.ts +6 -4
- package/lib/index.js +9 -33
- package/lib/lockfileFormatConverters.d.ts +1 -1
- package/lib/lockfileFormatConverters.js +34 -47
- package/lib/lockfileName.js +6 -9
- package/lib/logger.js +2 -5
- package/lib/read.d.ts +2 -2
- package/lib/read.js +53 -53
- package/lib/sortLockfileKeys.d.ts +2 -1
- package/lib/sortLockfileKeys.js +17 -19
- package/lib/write.d.ts +2 -1
- package/lib/write.js +64 -56
- package/lib/yamlDocuments.d.ts +16 -0
- package/lib/yamlDocuments.js +70 -0
- package/package.json +29 -29
- package/lib/errors/LockfileBreakingChangeError.js.map +0 -1
- package/lib/errors/index.js.map +0 -1
- package/lib/existsWantedLockfile.js.map +0 -1
- package/lib/getLockfileImporterId.js.map +0 -1
- package/lib/gitBranchLockfile.js.map +0 -1
- package/lib/gitMergeFile.js.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/lockfileFormatConverters.js.map +0 -1
- package/lib/lockfileName.js.map +0 -1
- package/lib/logger.js.map +0 -1
- package/lib/read.js.map +0 -1
- package/lib/sortLockfileKeys.js.map +0 -1
- package/lib/write.js.map +0 -1
package/lib/read.js
CHANGED
|
@@ -1,49 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
const index_js_1 = require("./errors/index.js");
|
|
21
|
-
const gitMergeFile_js_1 = require("./gitMergeFile.js");
|
|
22
|
-
const logger_js_1 = require("./logger.js");
|
|
23
|
-
const lockfileName_js_1 = require("./lockfileName.js");
|
|
24
|
-
const gitBranchLockfile_js_1 = require("./gitBranchLockfile.js");
|
|
25
|
-
const lockfileFormatConverters_js_1 = require("./lockfileFormatConverters.js");
|
|
26
|
-
async function readCurrentLockfile(pnpmInternalDir, opts) {
|
|
27
|
-
const lockfilePath = path_1.default.join(pnpmInternalDir, 'lock.yaml');
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import util from 'node:util';
|
|
4
|
+
import { LOCKFILE_VERSION, WANTED_LOCKFILE, } from '@pnpm/constants';
|
|
5
|
+
import { PnpmError } from '@pnpm/error';
|
|
6
|
+
import { mergeLockfileChanges } from '@pnpm/lockfile.merger';
|
|
7
|
+
import { comverToSemver } from 'comver-to-semver';
|
|
8
|
+
import yaml from 'js-yaml';
|
|
9
|
+
import semver from 'semver';
|
|
10
|
+
import stripBom from 'strip-bom';
|
|
11
|
+
import { LockfileBreakingChangeError } from './errors/index.js';
|
|
12
|
+
import { getGitBranchLockfileNames } from './gitBranchLockfile.js';
|
|
13
|
+
import { autofixMergeConflicts, isDiff } from './gitMergeFile.js';
|
|
14
|
+
import { convertToLockfileObject } from './lockfileFormatConverters.js';
|
|
15
|
+
import { getWantedLockfileName } from './lockfileName.js';
|
|
16
|
+
import { lockfileLogger as logger } from './logger.js';
|
|
17
|
+
import { extractMainDocument } from './yamlDocuments.js';
|
|
18
|
+
export async function readCurrentLockfile(pnpmInternalDir, opts) {
|
|
19
|
+
const lockfilePath = path.join(pnpmInternalDir, 'lock.yaml');
|
|
28
20
|
return (await _read(lockfilePath, pnpmInternalDir, opts)).lockfile;
|
|
29
21
|
}
|
|
30
|
-
async function readWantedLockfileAndAutofixConflicts(pkgPath, opts) {
|
|
22
|
+
export async function readWantedLockfileAndAutofixConflicts(pkgPath, opts) {
|
|
31
23
|
return _readWantedLockfile(pkgPath, {
|
|
32
24
|
...opts,
|
|
33
25
|
autofixMergeConflicts: true,
|
|
34
26
|
});
|
|
35
27
|
}
|
|
36
|
-
async function readWantedLockfile(pkgPath, opts) {
|
|
28
|
+
export async function readWantedLockfile(pkgPath, opts) {
|
|
37
29
|
return (await _readWantedLockfile(pkgPath, opts)).lockfile;
|
|
38
30
|
}
|
|
39
31
|
async function _read(lockfilePath, prefix, // only for logging
|
|
40
32
|
opts) {
|
|
41
33
|
let lockfileRawContent;
|
|
42
34
|
try {
|
|
43
|
-
lockfileRawContent = (
|
|
35
|
+
lockfileRawContent = stripBom(await fs.readFile(lockfilePath, 'utf8'));
|
|
44
36
|
}
|
|
45
37
|
catch (err) {
|
|
46
|
-
if (!(
|
|
38
|
+
if (!(util.types.isNativeError(err) && 'code' in err && err.code === 'ENOENT')) {
|
|
47
39
|
throw err;
|
|
48
40
|
}
|
|
49
41
|
return {
|
|
@@ -51,33 +43,41 @@ opts) {
|
|
|
51
43
|
hadConflicts: false,
|
|
52
44
|
};
|
|
53
45
|
}
|
|
46
|
+
// Skip the env lockfile document if present (first document in combined format)
|
|
47
|
+
lockfileRawContent = extractMainDocument(lockfileRawContent);
|
|
48
|
+
if (!lockfileRawContent.trim()) {
|
|
49
|
+
return {
|
|
50
|
+
lockfile: null,
|
|
51
|
+
hadConflicts: false,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
54
|
let lockfile;
|
|
55
55
|
let hadConflicts;
|
|
56
56
|
try {
|
|
57
|
-
lockfile =
|
|
57
|
+
lockfile = convertToLockfileObject(yaml.load(lockfileRawContent)); // eslint-disable-line
|
|
58
58
|
hadConflicts = false;
|
|
59
59
|
}
|
|
60
60
|
catch (err) {
|
|
61
|
-
if (!opts.autofixMergeConflicts || !
|
|
62
|
-
throw new
|
|
61
|
+
if (!opts.autofixMergeConflicts || !isDiff(lockfileRawContent)) {
|
|
62
|
+
throw new PnpmError('BROKEN_LOCKFILE', `The lockfile at "${lockfilePath}" is broken: ${err.message}`);
|
|
63
63
|
}
|
|
64
64
|
hadConflicts = true;
|
|
65
|
-
lockfile =
|
|
66
|
-
|
|
67
|
-
message: `Merge conflict detected in ${
|
|
65
|
+
lockfile = autofixMergeConflicts(lockfileRawContent);
|
|
66
|
+
logger.info({
|
|
67
|
+
message: `Merge conflict detected in ${WANTED_LOCKFILE} and successfully merged`,
|
|
68
68
|
prefix,
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
71
|
if (lockfile) {
|
|
72
|
-
const lockfileSemver = (
|
|
72
|
+
const lockfileSemver = comverToSemver((lockfile.lockfileVersion ?? 0).toString());
|
|
73
73
|
if (!opts.wantedVersions ||
|
|
74
74
|
opts.wantedVersions.length === 0 ||
|
|
75
75
|
opts.wantedVersions.some((wantedVersion) => {
|
|
76
|
-
if (
|
|
76
|
+
if (semver.major(lockfileSemver) !== semver.major(comverToSemver(wantedVersion)))
|
|
77
77
|
return false;
|
|
78
|
-
if (lockfile.lockfileVersion !== '6.1' &&
|
|
79
|
-
|
|
80
|
-
message: `Your ${
|
|
78
|
+
if (lockfile.lockfileVersion !== '6.1' && semver.gt(lockfileSemver, comverToSemver(wantedVersion))) {
|
|
79
|
+
logger.warn({
|
|
80
|
+
message: `Your ${WANTED_LOCKFILE} was generated by a newer version of pnpm. ` +
|
|
81
81
|
`It is a compatible version but it might get downgraded to version ${wantedVersion}`,
|
|
82
82
|
prefix,
|
|
83
83
|
});
|
|
@@ -88,15 +88,15 @@ opts) {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
if (opts.ignoreIncompatible) {
|
|
91
|
-
|
|
91
|
+
logger.warn({
|
|
92
92
|
message: `Ignoring not compatible lockfile at ${lockfilePath}`,
|
|
93
93
|
prefix,
|
|
94
94
|
});
|
|
95
95
|
return { lockfile: null, hadConflicts: false };
|
|
96
96
|
}
|
|
97
|
-
throw new
|
|
97
|
+
throw new LockfileBreakingChangeError(lockfilePath);
|
|
98
98
|
}
|
|
99
|
-
function createLockfileObject(importerIds, opts) {
|
|
99
|
+
export function createLockfileObject(importerIds, opts) {
|
|
100
100
|
const importers = {};
|
|
101
101
|
for (const importerId of importerIds) {
|
|
102
102
|
importers[importerId] = {
|
|
@@ -106,7 +106,7 @@ function createLockfileObject(importerIds, opts) {
|
|
|
106
106
|
}
|
|
107
107
|
return {
|
|
108
108
|
importers,
|
|
109
|
-
lockfileVersion: opts.lockfileVersion ||
|
|
109
|
+
lockfileVersion: opts.lockfileVersion || LOCKFILE_VERSION,
|
|
110
110
|
settings: {
|
|
111
111
|
autoInstallPeers: opts.autoInstallPeers,
|
|
112
112
|
excludeLinksFromLockfile: opts.excludeLinksFromLockfile,
|
|
@@ -115,17 +115,17 @@ function createLockfileObject(importerIds, opts) {
|
|
|
115
115
|
};
|
|
116
116
|
}
|
|
117
117
|
async function _readWantedLockfile(pkgPath, opts) {
|
|
118
|
-
const lockfileNames = [
|
|
118
|
+
const lockfileNames = [WANTED_LOCKFILE];
|
|
119
119
|
if (opts.useGitBranchLockfile) {
|
|
120
|
-
const gitBranchLockfileName = await
|
|
121
|
-
if (gitBranchLockfileName !==
|
|
120
|
+
const gitBranchLockfileName = await getWantedLockfileName(opts);
|
|
121
|
+
if (gitBranchLockfileName !== WANTED_LOCKFILE) {
|
|
122
122
|
lockfileNames.unshift(gitBranchLockfileName);
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
let result = { lockfile: null, hadConflicts: false };
|
|
126
126
|
/* eslint-disable no-await-in-loop */
|
|
127
127
|
for (const lockfileName of lockfileNames) {
|
|
128
|
-
result = await _read(
|
|
128
|
+
result = await _read(path.join(pkgPath, lockfileName), pkgPath, { ...opts, autofixMergeConflicts: true });
|
|
129
129
|
if (result.lockfile) {
|
|
130
130
|
if (opts.mergeGitBranchLockfiles) {
|
|
131
131
|
result.lockfile = await _mergeGitBranchLockfiles(result.lockfile, pkgPath, pkgPath, opts);
|
|
@@ -146,12 +146,12 @@ async function _mergeGitBranchLockfiles(lockfile, lockfileDir, prefix, opts) {
|
|
|
146
146
|
if (!gitBranchLockfile) {
|
|
147
147
|
continue;
|
|
148
148
|
}
|
|
149
|
-
mergedLockfile =
|
|
149
|
+
mergedLockfile = mergeLockfileChanges(mergedLockfile, gitBranchLockfile);
|
|
150
150
|
}
|
|
151
151
|
return mergedLockfile;
|
|
152
152
|
}
|
|
153
153
|
async function _readGitBranchLockfiles(lockfileDir, prefix, opts) {
|
|
154
|
-
const files = await
|
|
155
|
-
return Promise.all(files.map((file) => _read(
|
|
154
|
+
const files = await getGitBranchLockfileNames(lockfileDir);
|
|
155
|
+
return Promise.all(files.map((file) => _read(path.join(lockfileDir, file), prefix, opts)));
|
|
156
156
|
}
|
|
157
157
|
//# sourceMappingURL=read.js.map
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { EnvLockfile, LockfileFile } from '@pnpm/lockfile.types';
|
|
2
2
|
export declare function sortLockfileKeys(lockfile: LockfileFile): LockfileFile;
|
|
3
|
+
export declare function sortLockfileKeys(lockfile: EnvLockfile): EnvLockfile;
|
package/lib/sortLockfileKeys.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.sortLockfileKeys = sortLockfileKeys;
|
|
4
|
-
const object_key_sorting_1 = require("@pnpm/object.key-sorting");
|
|
1
|
+
import { sortDeepKeys, sortDirectKeys, sortKeysByPriority } from '@pnpm/object.key-sorting';
|
|
5
2
|
const ORDERED_KEYS = {
|
|
6
3
|
resolution: 1,
|
|
7
4
|
id: 2,
|
|
@@ -36,45 +33,46 @@ const ROOT_KEYS = [
|
|
|
36
33
|
'packages',
|
|
37
34
|
];
|
|
38
35
|
const ROOT_KEYS_ORDER = Object.fromEntries(ROOT_KEYS.map((key, index) => [key, index]));
|
|
39
|
-
function sortLockfileKeys(lockfile) {
|
|
36
|
+
export function sortLockfileKeys(lockfile) {
|
|
40
37
|
if (lockfile.importers != null) {
|
|
41
|
-
lockfile.importers =
|
|
38
|
+
lockfile.importers = sortDirectKeys(lockfile.importers);
|
|
42
39
|
for (const [importerId, importer] of Object.entries(lockfile.importers)) {
|
|
43
|
-
lockfile.importers[importerId] =
|
|
40
|
+
lockfile.importers[importerId] = sortKeysByPriority({
|
|
44
41
|
priority: ROOT_KEYS_ORDER,
|
|
45
42
|
deep: true,
|
|
46
43
|
}, importer);
|
|
47
44
|
}
|
|
48
45
|
}
|
|
49
46
|
if (lockfile.packages != null) {
|
|
50
|
-
lockfile.packages =
|
|
47
|
+
lockfile.packages = sortDirectKeys(lockfile.packages);
|
|
51
48
|
for (const [pkgId, pkg] of Object.entries(lockfile.packages)) {
|
|
52
|
-
lockfile.packages[pkgId] =
|
|
49
|
+
lockfile.packages[pkgId] = sortKeysByPriority({
|
|
53
50
|
priority: ORDERED_KEYS,
|
|
54
51
|
deep: true,
|
|
55
52
|
}, pkg);
|
|
56
53
|
}
|
|
57
54
|
}
|
|
58
55
|
if (lockfile.snapshots != null) {
|
|
59
|
-
lockfile.snapshots =
|
|
56
|
+
lockfile.snapshots = sortDirectKeys(lockfile.snapshots);
|
|
60
57
|
for (const [pkgId, pkg] of Object.entries(lockfile.snapshots)) {
|
|
61
|
-
lockfile.snapshots[pkgId] =
|
|
58
|
+
lockfile.snapshots[pkgId] = sortKeysByPriority({
|
|
62
59
|
priority: ORDERED_KEYS,
|
|
63
60
|
deep: true,
|
|
64
61
|
}, pkg);
|
|
65
62
|
}
|
|
66
63
|
}
|
|
67
|
-
if (lockfile.catalogs != null) {
|
|
68
|
-
lockfile.catalogs =
|
|
64
|
+
if ('catalogs' in lockfile && lockfile.catalogs != null) {
|
|
65
|
+
lockfile.catalogs = sortDirectKeys(lockfile.catalogs);
|
|
69
66
|
for (const [catalogName, catalog] of Object.entries(lockfile.catalogs)) {
|
|
70
|
-
lockfile.catalogs[catalogName] =
|
|
67
|
+
lockfile.catalogs[catalogName] = sortDeepKeys(catalog);
|
|
71
68
|
}
|
|
72
69
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
continue;
|
|
76
|
-
lockfile[key] = (0, object_key_sorting_1.sortDirectKeys)(lockfile[key]); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
70
|
+
if ('time' in lockfile && lockfile.time != null) {
|
|
71
|
+
lockfile.time = sortDirectKeys(lockfile.time);
|
|
77
72
|
}
|
|
78
|
-
|
|
73
|
+
if ('patchedDependencies' in lockfile && lockfile.patchedDependencies != null) {
|
|
74
|
+
lockfile.patchedDependencies = sortDirectKeys(lockfile.patchedDependencies);
|
|
75
|
+
}
|
|
76
|
+
return sortKeysByPriority({ priority: ROOT_KEYS_ORDER }, lockfile);
|
|
79
77
|
}
|
|
80
78
|
//# sourceMappingURL=sortLockfileKeys.js.map
|
package/lib/write.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { LockfileFile, LockfileObject } from '@pnpm/lockfile.types';
|
|
2
|
+
export declare function lockfileYamlDump(obj: object): string;
|
|
2
3
|
export declare function writeWantedLockfile(pkgPath: string, wantedLockfile: LockfileObject, opts?: {
|
|
3
4
|
useGitBranchLockfile?: boolean;
|
|
4
5
|
mergeGitBranchLockfiles?: boolean;
|
package/lib/write.js
CHANGED
|
@@ -1,105 +1,113 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const constants_1 = require("@pnpm/constants");
|
|
14
|
-
const rimraf_1 = __importDefault(require("@zkochan/rimraf"));
|
|
15
|
-
const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
16
|
-
const isEmpty_1 = __importDefault(require("ramda/src/isEmpty"));
|
|
17
|
-
const write_file_atomic_1 = __importDefault(require("write-file-atomic"));
|
|
18
|
-
const logger_js_1 = require("./logger.js");
|
|
19
|
-
const sortLockfileKeys_js_1 = require("./sortLockfileKeys.js");
|
|
20
|
-
const lockfileName_js_1 = require("./lockfileName.js");
|
|
21
|
-
const lockfileFormatConverters_js_1 = require("./lockfileFormatConverters.js");
|
|
22
|
-
async function writeFileAtomic(filename, data) {
|
|
23
|
-
return new Promise((resolve, reject) => {
|
|
24
|
-
(0, write_file_atomic_1.default)(filename, data, {}, (err) => {
|
|
25
|
-
(err != null) ? reject(err) : resolve();
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
}
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { WANTED_LOCKFILE } from '@pnpm/constants';
|
|
4
|
+
import { rimraf } from '@zkochan/rimraf';
|
|
5
|
+
import yaml from 'js-yaml';
|
|
6
|
+
import { isEmpty } from 'ramda';
|
|
7
|
+
import writeFileAtomic from 'write-file-atomic';
|
|
8
|
+
import { convertToLockfileFile } from './lockfileFormatConverters.js';
|
|
9
|
+
import { getWantedLockfileName } from './lockfileName.js';
|
|
10
|
+
import { lockfileLogger as logger } from './logger.js';
|
|
11
|
+
import { sortLockfileKeys } from './sortLockfileKeys.js';
|
|
12
|
+
import { streamReadFirstYamlDocument, YAML_DOCUMENT_SEPARATOR, YAML_DOCUMENT_START } from './yamlDocuments.js';
|
|
29
13
|
const LOCKFILE_YAML_FORMAT = {
|
|
30
14
|
blankLines: true,
|
|
31
|
-
lineWidth: -1,
|
|
15
|
+
lineWidth: -1,
|
|
32
16
|
noCompatMode: true,
|
|
33
17
|
noRefs: true,
|
|
34
18
|
sortKeys: false,
|
|
35
19
|
};
|
|
36
|
-
|
|
37
|
-
|
|
20
|
+
export function lockfileYamlDump(obj) {
|
|
21
|
+
return yaml.dump(obj, LOCKFILE_YAML_FORMAT);
|
|
22
|
+
}
|
|
23
|
+
export async function writeWantedLockfile(pkgPath, wantedLockfile, opts) {
|
|
24
|
+
const wantedLockfileName = await getWantedLockfileName(opts);
|
|
38
25
|
return writeLockfile(wantedLockfileName, pkgPath, wantedLockfile);
|
|
39
26
|
}
|
|
40
|
-
async function writeCurrentLockfile(virtualStoreDir, currentLockfile) {
|
|
27
|
+
export async function writeCurrentLockfile(virtualStoreDir, currentLockfile) {
|
|
41
28
|
// empty lockfile is not saved
|
|
42
29
|
if (isEmptyLockfile(currentLockfile)) {
|
|
43
|
-
await (
|
|
30
|
+
await rimraf(path.join(virtualStoreDir, 'lock.yaml'));
|
|
44
31
|
return;
|
|
45
32
|
}
|
|
46
|
-
await
|
|
33
|
+
await fs.mkdir(virtualStoreDir, { recursive: true });
|
|
47
34
|
return writeLockfile('lock.yaml', virtualStoreDir, currentLockfile);
|
|
48
35
|
}
|
|
49
36
|
async function writeLockfile(lockfileFilename, pkgPath, wantedLockfile) {
|
|
50
|
-
const lockfilePath =
|
|
51
|
-
const lockfileToStringify =
|
|
52
|
-
|
|
37
|
+
const lockfilePath = path.join(pkgPath, lockfileFilename);
|
|
38
|
+
const lockfileToStringify = convertToLockfileFile(wantedLockfile);
|
|
39
|
+
const yamlDoc = yamlStringify(lockfileToStringify);
|
|
40
|
+
if (lockfileFilename === WANTED_LOCKFILE) {
|
|
41
|
+
// Re-read the env document from the existing lockfile to preserve it.
|
|
42
|
+
// Ideally the env document would be captured during the initial lockfile read
|
|
43
|
+
// and passed through to the write functions, but that would require threading it
|
|
44
|
+
// through 25+ call sites. Re-reading is cheap since the file is likely still
|
|
45
|
+
// in the OS page cache and streaming stops at the first separator.
|
|
46
|
+
const envDoc = await streamReadFirstYamlDocument(lockfilePath);
|
|
47
|
+
const envPrefix = envDoc != null ? `${YAML_DOCUMENT_START}${envDoc}${YAML_DOCUMENT_SEPARATOR}` : '';
|
|
48
|
+
return writeFileAtomic(lockfilePath, `${envPrefix}${yamlDoc}`);
|
|
49
|
+
}
|
|
50
|
+
return writeFileAtomic(lockfilePath, yamlDoc);
|
|
53
51
|
}
|
|
54
|
-
function writeLockfileFile(lockfilePath, wantedLockfile) {
|
|
52
|
+
export function writeLockfileFile(lockfilePath, wantedLockfile) {
|
|
55
53
|
const yamlDoc = yamlStringify(wantedLockfile);
|
|
56
54
|
return writeFileAtomic(lockfilePath, yamlDoc);
|
|
57
55
|
}
|
|
58
56
|
function yamlStringify(lockfile) {
|
|
59
|
-
const sortedLockfile =
|
|
60
|
-
return
|
|
57
|
+
const sortedLockfile = sortLockfileKeys(lockfile);
|
|
58
|
+
return lockfileYamlDump(sortedLockfile);
|
|
61
59
|
}
|
|
62
|
-
function isEmptyLockfile(lockfile) {
|
|
63
|
-
return Object.values(lockfile.importers).every((importer) => (
|
|
60
|
+
export function isEmptyLockfile(lockfile) {
|
|
61
|
+
return Object.values(lockfile.importers).every((importer) => isEmpty(importer.specifiers ?? {}) && isEmpty(importer.dependencies ?? {}));
|
|
64
62
|
}
|
|
65
|
-
async function writeLockfiles(opts) {
|
|
66
|
-
const wantedLockfileName = await
|
|
67
|
-
const wantedLockfilePath =
|
|
68
|
-
const currentLockfilePath =
|
|
69
|
-
const wantedLockfileToStringify =
|
|
63
|
+
export async function writeLockfiles(opts) {
|
|
64
|
+
const wantedLockfileName = await getWantedLockfileName(opts);
|
|
65
|
+
const wantedLockfilePath = path.join(opts.wantedLockfileDir, wantedLockfileName);
|
|
66
|
+
const currentLockfilePath = path.join(opts.currentLockfileDir, 'lock.yaml');
|
|
67
|
+
const wantedLockfileToStringify = convertToLockfileFile(opts.wantedLockfile);
|
|
70
68
|
const yamlDoc = yamlStringify(wantedLockfileToStringify);
|
|
69
|
+
// Preserve the env lockfile document at the top of pnpm-lock.yaml
|
|
70
|
+
let envPrefix = '';
|
|
71
|
+
if (wantedLockfileName === WANTED_LOCKFILE) {
|
|
72
|
+
const envDoc = await streamReadFirstYamlDocument(wantedLockfilePath);
|
|
73
|
+
if (envDoc != null) {
|
|
74
|
+
envPrefix = `${YAML_DOCUMENT_START}${envDoc}${YAML_DOCUMENT_SEPARATOR}`;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const wantedYamlDoc = `${envPrefix}${yamlDoc}`;
|
|
71
78
|
// in most cases the `pnpm-lock.yaml` and `node_modules/.pnpm-lock.yaml` are equal
|
|
72
79
|
// in those cases the YAML document can be stringified only once for both files
|
|
73
80
|
// which is more efficient
|
|
74
81
|
if (opts.wantedLockfile === opts.currentLockfile) {
|
|
75
82
|
await Promise.all([
|
|
76
|
-
writeFileAtomic(wantedLockfilePath,
|
|
83
|
+
writeFileAtomic(wantedLockfilePath, wantedYamlDoc),
|
|
77
84
|
(async () => {
|
|
78
85
|
if (isEmptyLockfile(opts.wantedLockfile)) {
|
|
79
|
-
await (
|
|
86
|
+
await rimraf(currentLockfilePath);
|
|
80
87
|
}
|
|
81
88
|
else {
|
|
82
|
-
await
|
|
89
|
+
await fs.mkdir(path.dirname(currentLockfilePath), { recursive: true });
|
|
90
|
+
// Current lockfile (node_modules/.pnpm/lock.yaml) does not include the env document
|
|
83
91
|
await writeFileAtomic(currentLockfilePath, yamlDoc);
|
|
84
92
|
}
|
|
85
93
|
})(),
|
|
86
94
|
]);
|
|
87
95
|
return;
|
|
88
96
|
}
|
|
89
|
-
|
|
90
|
-
message: `\`${
|
|
97
|
+
logger.debug({
|
|
98
|
+
message: `\`${WANTED_LOCKFILE}\` differs from \`${path.relative(opts.wantedLockfileDir, currentLockfilePath)}\``,
|
|
91
99
|
prefix: opts.wantedLockfileDir,
|
|
92
100
|
});
|
|
93
|
-
const currentLockfileToStringify =
|
|
101
|
+
const currentLockfileToStringify = convertToLockfileFile(opts.currentLockfile);
|
|
94
102
|
const currentYamlDoc = yamlStringify(currentLockfileToStringify);
|
|
95
103
|
await Promise.all([
|
|
96
|
-
writeFileAtomic(wantedLockfilePath,
|
|
104
|
+
writeFileAtomic(wantedLockfilePath, wantedYamlDoc),
|
|
97
105
|
(async () => {
|
|
98
106
|
if (isEmptyLockfile(opts.wantedLockfile)) {
|
|
99
|
-
await (
|
|
107
|
+
await rimraf(currentLockfilePath);
|
|
100
108
|
}
|
|
101
109
|
else {
|
|
102
|
-
await
|
|
110
|
+
await fs.mkdir(path.dirname(currentLockfilePath), { recursive: true });
|
|
103
111
|
await writeFileAtomic(currentLockfilePath, currentYamlDoc);
|
|
104
112
|
}
|
|
105
113
|
})(),
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const YAML_DOCUMENT_SEPARATOR = "\n---\n";
|
|
2
|
+
export declare const YAML_DOCUMENT_START = "---\n";
|
|
3
|
+
/**
|
|
4
|
+
* Reads the first YAML document from a multi-document YAML file using streaming.
|
|
5
|
+
* The file must start with "---\n" to indicate it contains an env lockfile document.
|
|
6
|
+
* Stops reading as soon as the second document separator is found.
|
|
7
|
+
* Returns null if the file doesn't exist or doesn't start with "---\n".
|
|
8
|
+
*/
|
|
9
|
+
export declare function streamReadFirstYamlDocument(filePath: string): Promise<string | null>;
|
|
10
|
+
/**
|
|
11
|
+
* Extracts the main lockfile content (second YAML document) from a combined string.
|
|
12
|
+
* If the file starts with "---\n", returns the content after the separator.
|
|
13
|
+
* If there is no separator, returns empty string (file is env-only).
|
|
14
|
+
* Otherwise returns the entire content (no env document present).
|
|
15
|
+
*/
|
|
16
|
+
export declare function extractMainDocument(content: string): string;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { createReadStream } from 'node:fs';
|
|
2
|
+
import util from 'node:util';
|
|
3
|
+
import stripBom from 'strip-bom';
|
|
4
|
+
export const YAML_DOCUMENT_SEPARATOR = '\n---\n';
|
|
5
|
+
export const YAML_DOCUMENT_START = '---\n';
|
|
6
|
+
/**
|
|
7
|
+
* Reads the first YAML document from a multi-document YAML file using streaming.
|
|
8
|
+
* The file must start with "---\n" to indicate it contains an env lockfile document.
|
|
9
|
+
* Stops reading as soon as the second document separator is found.
|
|
10
|
+
* Returns null if the file doesn't exist or doesn't start with "---\n".
|
|
11
|
+
*/
|
|
12
|
+
export async function streamReadFirstYamlDocument(filePath) {
|
|
13
|
+
const stream = createReadStream(filePath, { encoding: 'utf8' });
|
|
14
|
+
const chunks = stream[Symbol.asyncIterator]();
|
|
15
|
+
let buffer = '';
|
|
16
|
+
try {
|
|
17
|
+
// Phase 1: verify the file starts with "---\n"
|
|
18
|
+
for (let chunk = await chunks.next(); !chunk.done; chunk = await chunks.next()) { // eslint-disable-line no-await-in-loop
|
|
19
|
+
if (buffer.length === 0) {
|
|
20
|
+
// Strip BOM from the first chunk. Safe because the stream uses utf8 encoding,
|
|
21
|
+
// so the 3-byte BOM is decoded into a single \uFEFF character in the first chunk.
|
|
22
|
+
buffer = stripBom(chunk.value);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
buffer += chunk.value;
|
|
26
|
+
}
|
|
27
|
+
if (buffer.length >= YAML_DOCUMENT_START.length)
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
if (!buffer.startsWith(YAML_DOCUMENT_START)) {
|
|
31
|
+
stream.destroy();
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
// Phase 2: find the second "---" separator
|
|
35
|
+
while (true) {
|
|
36
|
+
const sep = buffer.indexOf(YAML_DOCUMENT_SEPARATOR, YAML_DOCUMENT_START.length);
|
|
37
|
+
if (sep !== -1) {
|
|
38
|
+
stream.destroy();
|
|
39
|
+
return buffer.slice(YAML_DOCUMENT_START.length, sep);
|
|
40
|
+
}
|
|
41
|
+
const chunk = await chunks.next(); // eslint-disable-line no-await-in-loop
|
|
42
|
+
if (chunk.done)
|
|
43
|
+
break;
|
|
44
|
+
buffer += chunk.value;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
if (util.types.isNativeError(err) && 'code' in err && err.code === 'ENOENT') {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
throw err;
|
|
52
|
+
}
|
|
53
|
+
stream.destroy();
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Extracts the main lockfile content (second YAML document) from a combined string.
|
|
58
|
+
* If the file starts with "---\n", returns the content after the separator.
|
|
59
|
+
* If there is no separator, returns empty string (file is env-only).
|
|
60
|
+
* Otherwise returns the entire content (no env document present).
|
|
61
|
+
*/
|
|
62
|
+
export function extractMainDocument(content) {
|
|
63
|
+
if (!content.startsWith(YAML_DOCUMENT_START))
|
|
64
|
+
return content;
|
|
65
|
+
const sep = content.indexOf(YAML_DOCUMENT_SEPARATOR, YAML_DOCUMENT_START.length);
|
|
66
|
+
if (sep === -1)
|
|
67
|
+
return '';
|
|
68
|
+
return content.slice(sep + YAML_DOCUMENT_SEPARATOR.length);
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=yamlDocuments.js.map
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/lockfile.fs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1100.0.0",
|
|
4
4
|
"description": "Read/write pnpm-lock.yaml files",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
7
|
-
"
|
|
7
|
+
"pnpm11",
|
|
8
8
|
"lockfile",
|
|
9
9
|
"shrinkwrap"
|
|
10
10
|
],
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"bugs": {
|
|
16
16
|
"url": "https://github.com/pnpm/pnpm/issues"
|
|
17
17
|
},
|
|
18
|
-
"type": "
|
|
18
|
+
"type": "module",
|
|
19
19
|
"main": "lib/index.js",
|
|
20
20
|
"types": "lib/index.d.ts",
|
|
21
21
|
"exports": {
|
|
@@ -26,51 +26,51 @@
|
|
|
26
26
|
"!*.map"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@zkochan/rimraf": "^
|
|
30
|
-
"comver-to-semver": "^
|
|
29
|
+
"@zkochan/rimraf": "^4.0.0",
|
|
30
|
+
"comver-to-semver": "^2.0.0",
|
|
31
31
|
"js-yaml": "npm:@zkochan/js-yaml@0.0.11",
|
|
32
32
|
"normalize-path": "^3.0.0",
|
|
33
33
|
"ramda": "npm:@pnpm/ramda@0.28.1",
|
|
34
|
-
"semver": "^7.7.
|
|
35
|
-
"strip-bom": "^
|
|
36
|
-
"write-file-atomic": "^
|
|
37
|
-
"@pnpm/constants": "
|
|
38
|
-
"@pnpm/
|
|
39
|
-
"@pnpm/
|
|
40
|
-
"@pnpm/lockfile.
|
|
41
|
-
"@pnpm/
|
|
42
|
-
"@pnpm/
|
|
43
|
-
"@pnpm/object.key-sorting": "
|
|
44
|
-
"@pnpm/
|
|
45
|
-
"@pnpm/
|
|
34
|
+
"semver": "^7.7.2",
|
|
35
|
+
"strip-bom": "^5.0.0",
|
|
36
|
+
"write-file-atomic": "^7.0.0",
|
|
37
|
+
"@pnpm/constants": "1100.0.0",
|
|
38
|
+
"@pnpm/error": "1100.0.0",
|
|
39
|
+
"@pnpm/lockfile.merger": "1100.0.0",
|
|
40
|
+
"@pnpm/lockfile.types": "1100.0.0",
|
|
41
|
+
"@pnpm/lockfile.utils": "1100.0.0",
|
|
42
|
+
"@pnpm/network.git-utils": "1100.0.0",
|
|
43
|
+
"@pnpm/object.key-sorting": "1100.0.0",
|
|
44
|
+
"@pnpm/types": "1100.0.0",
|
|
45
|
+
"@pnpm/deps.path": "1100.0.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@pnpm/logger": ">=1001.0.0 <1002.0.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@jest/globals": "
|
|
51
|
+
"@jest/globals": "30.3.0",
|
|
52
52
|
"@types/js-yaml": "^4.0.9",
|
|
53
53
|
"@types/normalize-path": "^3.0.2",
|
|
54
|
-
"@types/ramda": "0.
|
|
55
|
-
"@types/semver": "7.
|
|
54
|
+
"@types/ramda": "0.31.1",
|
|
55
|
+
"@types/semver": "7.7.1",
|
|
56
56
|
"@types/write-file-atomic": "^4.0.3",
|
|
57
|
-
"tempy": "
|
|
58
|
-
"write-yaml-file": "^
|
|
57
|
+
"tempy": "3.0.0",
|
|
58
|
+
"write-yaml-file": "^6.0.0",
|
|
59
59
|
"yaml-tag": "1.1.0",
|
|
60
|
-
"@pnpm/lockfile.fs": "
|
|
61
|
-
"@pnpm/logger": "
|
|
60
|
+
"@pnpm/lockfile.fs": "1100.0.0",
|
|
61
|
+
"@pnpm/logger": "1100.0.0"
|
|
62
62
|
},
|
|
63
63
|
"engines": {
|
|
64
|
-
"node": ">=
|
|
64
|
+
"node": ">=22.13"
|
|
65
65
|
},
|
|
66
66
|
"jest": {
|
|
67
67
|
"preset": "@pnpm/jest-config"
|
|
68
68
|
},
|
|
69
69
|
"scripts": {
|
|
70
70
|
"lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
71
|
+
"test": "pn compile && pn .test",
|
|
72
|
+
"compile": "tsgo --build && pn lint --fix",
|
|
73
|
+
"start": "tsgo --watch",
|
|
74
|
+
".test": "cross-env NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169\" jest"
|
|
75
75
|
}
|
|
76
76
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"LockfileBreakingChangeError.js","sourceRoot":"","sources":["../../src/errors/LockfileBreakingChangeError.ts"],"names":[],"mappings":";;;AAAA,uCAAuC;AAEvC,MAAa,2BAA4B,SAAQ,iBAAS;IACjD,QAAQ,CAAQ;IACvB,YAAa,QAAgB;QAC3B,KAAK,CAAC,0BAA0B,EAAE,YAAY,QAAQ,mCAAmC,CAAC,CAAA;QAC1F,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;IAC1B,CAAC;CACF;AAND,kEAMC"}
|