@pnpm/lockfile.fs 1001.1.32 → 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.
Files changed (39) hide show
  1. package/lib/envLockfile.d.ts +4 -0
  2. package/lib/envLockfile.js +72 -0
  3. package/lib/errors/LockfileBreakingChangeError.js +2 -6
  4. package/lib/errors/index.js +1 -5
  5. package/lib/existsWantedLockfile.d.ts +2 -2
  6. package/lib/existsWantedLockfile.js +6 -12
  7. package/lib/getLockfileImporterId.d.ts +1 -1
  8. package/lib/getLockfileImporterId.js +4 -10
  9. package/lib/gitBranchLockfile.js +8 -15
  10. package/lib/gitMergeFile.d.ts +1 -1
  11. package/lib/gitMergeFile.js +6 -13
  12. package/lib/index.d.ts +6 -4
  13. package/lib/index.js +9 -33
  14. package/lib/lockfileFormatConverters.d.ts +1 -1
  15. package/lib/lockfileFormatConverters.js +34 -47
  16. package/lib/lockfileName.js +6 -9
  17. package/lib/logger.js +2 -5
  18. package/lib/read.d.ts +2 -2
  19. package/lib/read.js +52 -63
  20. package/lib/sortLockfileKeys.d.ts +2 -1
  21. package/lib/sortLockfileKeys.js +17 -19
  22. package/lib/write.d.ts +2 -1
  23. package/lib/write.js +64 -56
  24. package/lib/yamlDocuments.d.ts +16 -0
  25. package/lib/yamlDocuments.js +70 -0
  26. package/package.json +30 -30
  27. package/lib/errors/LockfileBreakingChangeError.js.map +0 -1
  28. package/lib/errors/index.js.map +0 -1
  29. package/lib/existsWantedLockfile.js.map +0 -1
  30. package/lib/getLockfileImporterId.js.map +0 -1
  31. package/lib/gitBranchLockfile.js.map +0 -1
  32. package/lib/gitMergeFile.js.map +0 -1
  33. package/lib/index.js.map +0 -1
  34. package/lib/lockfileFormatConverters.js.map +0 -1
  35. package/lib/lockfileName.js.map +0 -1
  36. package/lib/logger.js.map +0 -1
  37. package/lib/read.js.map +0 -1
  38. package/lib/sortLockfileKeys.js.map +0 -1
  39. package/lib/write.js.map +0 -1
package/lib/read.js CHANGED
@@ -1,49 +1,41 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.readCurrentLockfile = readCurrentLockfile;
7
- exports.readWantedLockfileAndAutofixConflicts = readWantedLockfileAndAutofixConflicts;
8
- exports.readWantedLockfile = readWantedLockfile;
9
- exports.createLockfileObject = createLockfileObject;
10
- const fs_1 = require("fs");
11
- const path_1 = __importDefault(require("path"));
12
- const util_1 = __importDefault(require("util"));
13
- const constants_1 = require("@pnpm/constants");
14
- const error_1 = require("@pnpm/error");
15
- const lockfile_merger_1 = require("@pnpm/lockfile.merger");
16
- const comver_to_semver_1 = __importDefault(require("comver-to-semver"));
17
- const js_yaml_1 = __importDefault(require("js-yaml"));
18
- const semver_1 = __importDefault(require("semver"));
19
- const strip_bom_1 = __importDefault(require("strip-bom"));
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 = (0, strip_bom_1.default)(await fs_1.promises.readFile(lockfilePath, 'utf8'));
35
+ lockfileRawContent = stripBom(await fs.readFile(lockfilePath, 'utf8'));
44
36
  }
45
37
  catch (err) {
46
- if (!(util_1.default.types.isNativeError(err) && 'code' in err && err.code === 'ENOENT')) {
38
+ if (!(util.types.isNativeError(err) && 'code' in err && err.code === 'ENOENT')) {
47
39
  throw err;
48
40
  }
49
41
  return {
@@ -51,36 +43,41 @@ opts) {
51
43
  hadConflicts: false,
52
44
  };
53
45
  }
54
- // Skip the first YAML document if the file contains two documents (v11 format).
55
- // The first document is the env lockfile; the second is the actual lockfile.
46
+ // Skip the env lockfile document if present (first document in combined format)
56
47
  lockfileRawContent = extractMainDocument(lockfileRawContent);
48
+ if (!lockfileRawContent.trim()) {
49
+ return {
50
+ lockfile: null,
51
+ hadConflicts: false,
52
+ };
53
+ }
57
54
  let lockfile;
58
55
  let hadConflicts;
59
56
  try {
60
- lockfile = (0, lockfileFormatConverters_js_1.convertToLockfileObject)(js_yaml_1.default.load(lockfileRawContent)); // eslint-disable-line
57
+ lockfile = convertToLockfileObject(yaml.load(lockfileRawContent)); // eslint-disable-line
61
58
  hadConflicts = false;
62
59
  }
63
60
  catch (err) {
64
- if (!opts.autofixMergeConflicts || !(0, gitMergeFile_js_1.isDiff)(lockfileRawContent)) {
65
- throw new error_1.PnpmError('BROKEN_LOCKFILE', `The lockfile at "${lockfilePath}" is broken: ${err.message}`);
61
+ if (!opts.autofixMergeConflicts || !isDiff(lockfileRawContent)) {
62
+ throw new PnpmError('BROKEN_LOCKFILE', `The lockfile at "${lockfilePath}" is broken: ${err.message}`);
66
63
  }
67
64
  hadConflicts = true;
68
- lockfile = (0, gitMergeFile_js_1.autofixMergeConflicts)(lockfileRawContent);
69
- logger_js_1.lockfileLogger.info({
70
- message: `Merge conflict detected in ${constants_1.WANTED_LOCKFILE} and successfully merged`,
65
+ lockfile = autofixMergeConflicts(lockfileRawContent);
66
+ logger.info({
67
+ message: `Merge conflict detected in ${WANTED_LOCKFILE} and successfully merged`,
71
68
  prefix,
72
69
  });
73
70
  }
74
71
  if (lockfile) {
75
- const lockfileSemver = (0, comver_to_semver_1.default)((lockfile.lockfileVersion ?? 0).toString());
72
+ const lockfileSemver = comverToSemver((lockfile.lockfileVersion ?? 0).toString());
76
73
  if (!opts.wantedVersions ||
77
74
  opts.wantedVersions.length === 0 ||
78
75
  opts.wantedVersions.some((wantedVersion) => {
79
- if (semver_1.default.major(lockfileSemver) !== semver_1.default.major((0, comver_to_semver_1.default)(wantedVersion)))
76
+ if (semver.major(lockfileSemver) !== semver.major(comverToSemver(wantedVersion)))
80
77
  return false;
81
- if (lockfile.lockfileVersion !== '6.1' && semver_1.default.gt(lockfileSemver, (0, comver_to_semver_1.default)(wantedVersion))) {
82
- logger_js_1.lockfileLogger.warn({
83
- message: `Your ${constants_1.WANTED_LOCKFILE} was generated by a newer version of pnpm. ` +
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. ` +
84
81
  `It is a compatible version but it might get downgraded to version ${wantedVersion}`,
85
82
  prefix,
86
83
  });
@@ -91,15 +88,15 @@ opts) {
91
88
  }
92
89
  }
93
90
  if (opts.ignoreIncompatible) {
94
- logger_js_1.lockfileLogger.warn({
91
+ logger.warn({
95
92
  message: `Ignoring not compatible lockfile at ${lockfilePath}`,
96
93
  prefix,
97
94
  });
98
95
  return { lockfile: null, hadConflicts: false };
99
96
  }
100
- throw new index_js_1.LockfileBreakingChangeError(lockfilePath);
97
+ throw new LockfileBreakingChangeError(lockfilePath);
101
98
  }
102
- function createLockfileObject(importerIds, opts) {
99
+ export function createLockfileObject(importerIds, opts) {
103
100
  const importers = {};
104
101
  for (const importerId of importerIds) {
105
102
  importers[importerId] = {
@@ -109,7 +106,7 @@ function createLockfileObject(importerIds, opts) {
109
106
  }
110
107
  return {
111
108
  importers,
112
- lockfileVersion: opts.lockfileVersion || constants_1.LOCKFILE_VERSION,
109
+ lockfileVersion: opts.lockfileVersion || LOCKFILE_VERSION,
113
110
  settings: {
114
111
  autoInstallPeers: opts.autoInstallPeers,
115
112
  excludeLinksFromLockfile: opts.excludeLinksFromLockfile,
@@ -118,17 +115,17 @@ function createLockfileObject(importerIds, opts) {
118
115
  };
119
116
  }
120
117
  async function _readWantedLockfile(pkgPath, opts) {
121
- const lockfileNames = [constants_1.WANTED_LOCKFILE];
118
+ const lockfileNames = [WANTED_LOCKFILE];
122
119
  if (opts.useGitBranchLockfile) {
123
- const gitBranchLockfileName = await (0, lockfileName_js_1.getWantedLockfileName)(opts);
124
- if (gitBranchLockfileName !== constants_1.WANTED_LOCKFILE) {
120
+ const gitBranchLockfileName = await getWantedLockfileName(opts);
121
+ if (gitBranchLockfileName !== WANTED_LOCKFILE) {
125
122
  lockfileNames.unshift(gitBranchLockfileName);
126
123
  }
127
124
  }
128
125
  let result = { lockfile: null, hadConflicts: false };
129
126
  /* eslint-disable no-await-in-loop */
130
127
  for (const lockfileName of lockfileNames) {
131
- result = await _read(path_1.default.join(pkgPath, lockfileName), pkgPath, { ...opts, autofixMergeConflicts: true });
128
+ result = await _read(path.join(pkgPath, lockfileName), pkgPath, { ...opts, autofixMergeConflicts: true });
132
129
  if (result.lockfile) {
133
130
  if (opts.mergeGitBranchLockfiles) {
134
131
  result.lockfile = await _mergeGitBranchLockfiles(result.lockfile, pkgPath, pkgPath, opts);
@@ -149,20 +146,12 @@ async function _mergeGitBranchLockfiles(lockfile, lockfileDir, prefix, opts) {
149
146
  if (!gitBranchLockfile) {
150
147
  continue;
151
148
  }
152
- mergedLockfile = (0, lockfile_merger_1.mergeLockfileChanges)(mergedLockfile, gitBranchLockfile);
149
+ mergedLockfile = mergeLockfileChanges(mergedLockfile, gitBranchLockfile);
153
150
  }
154
151
  return mergedLockfile;
155
152
  }
156
153
  async function _readGitBranchLockfiles(lockfileDir, prefix, opts) {
157
- const files = await (0, gitBranchLockfile_js_1.getGitBranchLockfileNames)(lockfileDir);
158
- return Promise.all(files.map((file) => _read(path_1.default.join(lockfileDir, file), prefix, opts)));
159
- }
160
- function extractMainDocument(content) {
161
- if (!content.startsWith('---\n'))
162
- return content;
163
- const sep = content.indexOf('\n---\n', '---\n'.length);
164
- if (sep === -1)
165
- return content;
166
- return content.slice(sep + '\n---\n'.length);
154
+ const files = await getGitBranchLockfileNames(lockfileDir);
155
+ return Promise.all(files.map((file) => _read(path.join(lockfileDir, file), prefix, opts)));
167
156
  }
168
157
  //# sourceMappingURL=read.js.map
@@ -1,2 +1,3 @@
1
- import { type LockfileFile } from '@pnpm/lockfile.types';
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;
@@ -1,7 +1,4 @@
1
- "use strict";
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 = (0, object_key_sorting_1.sortDirectKeys)(lockfile.importers);
38
+ lockfile.importers = sortDirectKeys(lockfile.importers);
42
39
  for (const [importerId, importer] of Object.entries(lockfile.importers)) {
43
- lockfile.importers[importerId] = (0, object_key_sorting_1.sortKeysByPriority)({
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 = (0, object_key_sorting_1.sortDirectKeys)(lockfile.packages);
47
+ lockfile.packages = sortDirectKeys(lockfile.packages);
51
48
  for (const [pkgId, pkg] of Object.entries(lockfile.packages)) {
52
- lockfile.packages[pkgId] = (0, object_key_sorting_1.sortKeysByPriority)({
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 = (0, object_key_sorting_1.sortDirectKeys)(lockfile.snapshots);
56
+ lockfile.snapshots = sortDirectKeys(lockfile.snapshots);
60
57
  for (const [pkgId, pkg] of Object.entries(lockfile.snapshots)) {
61
- lockfile.snapshots[pkgId] = (0, object_key_sorting_1.sortKeysByPriority)({
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 = (0, object_key_sorting_1.sortDirectKeys)(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] = (0, object_key_sorting_1.sortDeepKeys)(catalog);
67
+ lockfile.catalogs[catalogName] = sortDeepKeys(catalog);
71
68
  }
72
69
  }
73
- for (const key of ['time', 'patchedDependencies']) {
74
- if (!lockfile[key])
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
- return (0, object_key_sorting_1.sortKeysByPriority)({ priority: ROOT_KEYS_ORDER }, lockfile);
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 { type LockfileObject, type LockfileFile } from '@pnpm/lockfile.types';
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
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.writeWantedLockfile = writeWantedLockfile;
7
- exports.writeCurrentLockfile = writeCurrentLockfile;
8
- exports.writeLockfileFile = writeLockfileFile;
9
- exports.isEmptyLockfile = isEmptyLockfile;
10
- exports.writeLockfiles = writeLockfiles;
11
- const fs_1 = require("fs");
12
- const path_1 = __importDefault(require("path"));
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, // This is setting line width to never wrap
15
+ lineWidth: -1,
32
16
  noCompatMode: true,
33
17
  noRefs: true,
34
18
  sortKeys: false,
35
19
  };
36
- async function writeWantedLockfile(pkgPath, wantedLockfile, opts) {
37
- const wantedLockfileName = await (0, lockfileName_js_1.getWantedLockfileName)(opts);
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 (0, rimraf_1.default)(path_1.default.join(virtualStoreDir, 'lock.yaml'));
30
+ await rimraf(path.join(virtualStoreDir, 'lock.yaml'));
44
31
  return;
45
32
  }
46
- await fs_1.promises.mkdir(virtualStoreDir, { recursive: true });
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 = path_1.default.join(pkgPath, lockfileFilename);
51
- const lockfileToStringify = (0, lockfileFormatConverters_js_1.convertToLockfileFile)(wantedLockfile);
52
- return writeLockfileFile(lockfilePath, lockfileToStringify);
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 = (0, sortLockfileKeys_js_1.sortLockfileKeys)(lockfile);
60
- return js_yaml_1.default.dump(sortedLockfile, LOCKFILE_YAML_FORMAT);
57
+ const sortedLockfile = sortLockfileKeys(lockfile);
58
+ return lockfileYamlDump(sortedLockfile);
61
59
  }
62
- function isEmptyLockfile(lockfile) {
63
- return Object.values(lockfile.importers).every((importer) => (0, isEmpty_1.default)(importer.specifiers ?? {}) && (0, isEmpty_1.default)(importer.dependencies ?? {}));
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 (0, lockfileName_js_1.getWantedLockfileName)(opts);
67
- const wantedLockfilePath = path_1.default.join(opts.wantedLockfileDir, wantedLockfileName);
68
- const currentLockfilePath = path_1.default.join(opts.currentLockfileDir, 'lock.yaml');
69
- const wantedLockfileToStringify = (0, lockfileFormatConverters_js_1.convertToLockfileFile)(opts.wantedLockfile);
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, yamlDoc),
83
+ writeFileAtomic(wantedLockfilePath, wantedYamlDoc),
77
84
  (async () => {
78
85
  if (isEmptyLockfile(opts.wantedLockfile)) {
79
- await (0, rimraf_1.default)(currentLockfilePath);
86
+ await rimraf(currentLockfilePath);
80
87
  }
81
88
  else {
82
- await fs_1.promises.mkdir(path_1.default.dirname(currentLockfilePath), { recursive: true });
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
- logger_js_1.lockfileLogger.debug({
90
- message: `\`${constants_1.WANTED_LOCKFILE}\` differs from \`${path_1.default.relative(opts.wantedLockfileDir, currentLockfilePath)}\``,
97
+ logger.debug({
98
+ message: `\`${WANTED_LOCKFILE}\` differs from \`${path.relative(opts.wantedLockfileDir, currentLockfilePath)}\``,
91
99
  prefix: opts.wantedLockfileDir,
92
100
  });
93
- const currentLockfileToStringify = (0, lockfileFormatConverters_js_1.convertToLockfileFile)(opts.currentLockfile);
101
+ const currentLockfileToStringify = convertToLockfileFile(opts.currentLockfile);
94
102
  const currentYamlDoc = yamlStringify(currentLockfileToStringify);
95
103
  await Promise.all([
96
- writeFileAtomic(wantedLockfilePath, yamlDoc),
104
+ writeFileAtomic(wantedLockfilePath, wantedYamlDoc),
97
105
  (async () => {
98
106
  if (isEmptyLockfile(opts.wantedLockfile)) {
99
- await (0, rimraf_1.default)(currentLockfilePath);
107
+ await rimraf(currentLockfilePath);
100
108
  }
101
109
  else {
102
- await fs_1.promises.mkdir(path_1.default.dirname(currentLockfilePath), { recursive: true });
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