@pnpm/releasing.commands 1100.7.0 → 1100.7.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.
Files changed (95) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/lib/change/index.d.ts +42 -0
  3. package/lib/change/index.js +248 -0
  4. package/lib/deploy/createDeployFiles.d.ts +26 -0
  5. package/lib/deploy/createDeployFiles.js +255 -0
  6. package/lib/deploy/deploy.d.ts +12 -0
  7. package/lib/deploy/deploy.js +398 -0
  8. package/lib/deploy/deployHook.d.ts +2 -0
  9. package/lib/deploy/deployHook.js +15 -0
  10. package/lib/deploy/index.d.ts +2 -0
  11. package/lib/deploy/index.js +3 -0
  12. package/lib/index.d.ts +7 -0
  13. package/lib/lane/index.d.ts +24 -0
  14. package/lib/lane/index.js +157 -0
  15. package/lib/pack-app/index.d.ts +2 -0
  16. package/lib/pack-app/index.js +3 -0
  17. package/lib/pack-app/packApp.d.ts +22 -0
  18. package/lib/pack-app/packApp.js +558 -0
  19. package/lib/publish/FailedToPublishError.d.ts +22 -0
  20. package/lib/publish/FailedToPublishError.js +40 -0
  21. package/lib/publish/batchPublish.d.ts +20 -0
  22. package/lib/publish/batchPublish.js +201 -0
  23. package/lib/publish/displayError.d.ts +1 -0
  24. package/lib/publish/displayError.js +23 -0
  25. package/lib/publish/executeTokenHelper.d.ts +4 -0
  26. package/lib/publish/executeTokenHelper.js +17 -0
  27. package/lib/publish/extractManifestFromPacked.d.ts +19 -0
  28. package/lib/publish/extractManifestFromPacked.js +110 -0
  29. package/lib/publish/index.d.ts +3 -0
  30. package/lib/publish/index.js +4 -0
  31. package/lib/publish/oidc/authToken.d.ts +73 -0
  32. package/lib/publish/oidc/authToken.js +97 -0
  33. package/lib/publish/oidc/idToken.d.ts +76 -0
  34. package/lib/publish/oidc/idToken.js +90 -0
  35. package/lib/publish/oidc/provenance.d.ts +73 -0
  36. package/lib/publish/oidc/provenance.js +91 -0
  37. package/lib/publish/otp.d.ts +38 -0
  38. package/lib/publish/otp.js +41 -0
  39. package/lib/publish/otpEnv.d.ts +7 -0
  40. package/lib/publish/otpEnv.js +5 -0
  41. package/lib/publish/pack.d.ts +34 -0
  42. package/lib/publish/pack.js +408 -0
  43. package/lib/publish/previousChangelog.d.ts +25 -0
  44. package/lib/publish/previousChangelog.js +194 -0
  45. package/lib/publish/publish.d.ts +40 -0
  46. package/lib/publish/publish.js +256 -0
  47. package/lib/publish/publishPackedPkg.d.ts +79 -0
  48. package/lib/publish/publishPackedPkg.js +298 -0
  49. package/lib/publish/recursivePublish.d.ts +18 -0
  50. package/lib/publish/recursivePublish.js +132 -0
  51. package/lib/publish/registryConfigKeys.d.ts +30 -0
  52. package/lib/publish/registryConfigKeys.js +50 -0
  53. package/lib/publish/utils/shared-context.d.ts +7 -0
  54. package/lib/publish/utils/shared-context.js +20 -0
  55. package/lib/resolveUnpublishedDirs.d.ts +10 -0
  56. package/lib/resolveUnpublishedDirs.js +14 -0
  57. package/lib/stage/approve.d.ts +2 -0
  58. package/lib/stage/approve.js +14 -0
  59. package/lib/stage/context.d.ts +14 -0
  60. package/lib/stage/context.js +25 -0
  61. package/lib/stage/download.d.ts +2 -0
  62. package/lib/stage/download.js +32 -0
  63. package/lib/stage/errors.d.ts +15 -0
  64. package/lib/stage/errors.js +17 -0
  65. package/lib/stage/help.d.ts +1 -0
  66. package/lib/stage/help.js +84 -0
  67. package/lib/stage/index.d.ts +13 -0
  68. package/lib/stage/index.js +57 -0
  69. package/lib/stage/list.d.ts +2 -0
  70. package/lib/stage/list.js +49 -0
  71. package/lib/stage/parsing.d.ts +6 -0
  72. package/lib/stage/parsing.js +27 -0
  73. package/lib/stage/publish.d.ts +7 -0
  74. package/lib/stage/publish.js +38 -0
  75. package/lib/stage/reject.d.ts +2 -0
  76. package/lib/stage/reject.js +16 -0
  77. package/lib/stage/rendering.d.ts +11 -0
  78. package/lib/stage/rendering.js +50 -0
  79. package/lib/stage/request.d.ts +29 -0
  80. package/lib/stage/request.js +110 -0
  81. package/lib/stage/types.d.ts +38 -0
  82. package/lib/stage/types.js +3 -0
  83. package/lib/stage/view.d.ts +2 -0
  84. package/lib/stage/view.js +14 -0
  85. package/lib/tarball/index.d.ts +2 -0
  86. package/lib/tarball/index.js +3 -0
  87. package/lib/tarball/publishSummary.d.ts +47 -0
  88. package/lib/tarball/publishSummary.js +36 -0
  89. package/lib/tarball/safeTarballFilename.d.ts +8 -0
  90. package/lib/tarball/safeTarballFilename.js +21 -0
  91. package/lib/tarball/summarizeTarball.d.ts +12 -0
  92. package/lib/tarball/summarizeTarball.js +84 -0
  93. package/lib/version/index.d.ts +35 -0
  94. package/lib/version/index.js +360 -0
  95. package/package.json +42 -42
package/CHANGELOG.md CHANGED
@@ -1,5 +1,50 @@
1
1
  # @pnpm/releasing.commands
2
2
 
3
+ ## 1100.7.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Republished every package: the tarballs published by the v11.13.1 through v11.16.0 releases were missing most of their compiled files due to a packing bug [#13164](https://github.com/pnpm/pnpm/issues/13164).
8
+
9
+ - Support the `from-git` argument in the `pnpm version` command.
10
+
11
+ - Updated dependencies:
12
+ - @pnpm/bins.resolver@1100.0.11
13
+ - @pnpm/catalogs.types@1100.0.1
14
+ - @pnpm/cli.common-cli-options-help@1100.0.3
15
+ - @pnpm/cli.utils@1101.0.19
16
+ - @pnpm/config.pick-registry-for-package@1100.0.12
17
+ - @pnpm/config.reader@1101.14.0
18
+ - @pnpm/constants@1100.0.1
19
+ - @pnpm/deps.path@1100.0.11
20
+ - @pnpm/engine.runtime.commands@1100.1.16
21
+ - @pnpm/engine.runtime.node-resolver@1101.1.18
22
+ - @pnpm/error@1100.1.0
23
+ - @pnpm/exec.lifecycle@1100.1.8
24
+ - @pnpm/exec.pnpm-cli-runner@1100.0.2
25
+ - @pnpm/fetching.directory-fetcher@1100.0.25
26
+ - @pnpm/fetching.types@1100.0.3
27
+ - @pnpm/fs.indexed-pkg-importer@1100.0.21
28
+ - @pnpm/fs.is-empty-dir-or-nothing@1100.0.1
29
+ - @pnpm/fs.packlist@1100.0.4
30
+ - @pnpm/installing.client@1100.2.20
31
+ - @pnpm/installing.commands@1100.12.0
32
+ - @pnpm/lockfile.fs@1100.1.14
33
+ - @pnpm/lockfile.types@1100.0.16
34
+ - @pnpm/network.auth-header@1101.1.6
35
+ - @pnpm/network.fetch@1100.1.8
36
+ - @pnpm/network.git-utils@1100.0.3
37
+ - @pnpm/network.web-auth@1101.3.0
38
+ - @pnpm/releasing.exportable-manifest@1100.1.15
39
+ - @pnpm/releasing.versioning@1100.2.1
40
+ - @pnpm/resolving.npm-resolver@1102.1.8
41
+ - @pnpm/resolving.registry.types@1100.1.6
42
+ - @pnpm/resolving.resolver-base@1100.5.4
43
+ - @pnpm/types@1101.6.0
44
+ - @pnpm/workspace.projects-filter@1100.0.32
45
+ - @pnpm/workspace.projects-sorter@1100.0.11
46
+ - @pnpm/workspace.workspace-manifest-writer@1100.0.18
47
+
3
48
  ## 1100.7.0
4
49
 
5
50
  ### Minor Changes
@@ -0,0 +1,42 @@
1
+ import type { Config } from '@pnpm/config.reader';
2
+ import { type ChangeIntent, type ReleasePlan, type WorkspaceProject } from '@pnpm/releasing.versioning';
3
+ import type { Project, VersioningSettings } from '@pnpm/types';
4
+ import { type UnpublishedProbeOptions } from '../resolveUnpublishedDirs.js';
5
+ export declare function rcOptionsTypes(): Record<string, unknown>;
6
+ export declare function cliOptionsTypes(): Record<string, unknown>;
7
+ export declare const commandNames: string[];
8
+ export declare function help(): string;
9
+ export type ChangeCommandOptions = Pick<Config, 'changedFilesIgnorePattern' | 'dir' | 'testPattern' | 'versioning' | 'workspaceDir'> & UnpublishedProbeOptions & {
10
+ allProjects?: Project[];
11
+ bump?: string;
12
+ summary?: string;
13
+ };
14
+ export declare function handler(opts: ChangeCommandOptions, params: string[]): Promise<string>;
15
+ export declare function renderReleasePlan(plan: ReleasePlan): string;
16
+ export interface ReleasableProject {
17
+ name: string;
18
+ /** Workspace-relative project directory. */
19
+ dir: string;
20
+ /**
21
+ * How an intent file or versioning config should reference this project:
22
+ * the bare name, or the `./`-prefixed directory when the name is shared by
23
+ * several workspace projects.
24
+ */
25
+ ref: string;
26
+ }
27
+ /**
28
+ * The projects a change intent may demand a release from: named, carrying a
29
+ * valid semver version, and not frozen by `versioning.ignore`. Matches the
30
+ * participant set of the release-plan assembler.
31
+ */
32
+ export declare function getReleasableProjects(allProjects: Array<Pick<Project, 'manifest' | 'rootDir'>>, workspaceDir: string, versioning?: VersioningSettings): ReleasableProject[];
33
+ export declare function toWorkspaceProjects(allProjects: Array<Pick<Project, 'manifest' | 'rootDir'>>): WorkspaceProject[];
34
+ export type { ChangeIntent };
35
+ export declare const change: {
36
+ handler: typeof handler;
37
+ help: typeof help;
38
+ commandNames: string[];
39
+ cliOptionsTypes: typeof cliOptionsTypes;
40
+ rcOptionsTypes: typeof rcOptionsTypes;
41
+ recursiveByDefault: boolean;
42
+ };
@@ -0,0 +1,248 @@
1
+ import { checkbox, input, Separator } from '@inquirer/prompts';
2
+ import { PnpmError } from '@pnpm/error';
3
+ import { assembleReleasePlan, BUMP_TYPES, indexProjectRefs, readChangeIntents, readLedger, toProjectDir, writeChangeIntent, } from '@pnpm/releasing.versioning';
4
+ import { getChangedProjects } from '@pnpm/workspace.projects-filter';
5
+ import { safeExeca as execa } from 'execa';
6
+ import { renderHelp } from 'render-help';
7
+ import { valid } from 'semver';
8
+ import { resolveUnpublishedDirs } from '../resolveUnpublishedDirs.js';
9
+ export function rcOptionsTypes() {
10
+ return {};
11
+ }
12
+ export function cliOptionsTypes() {
13
+ return {
14
+ bump: String,
15
+ summary: String,
16
+ recursive: Boolean,
17
+ };
18
+ }
19
+ export const commandNames = ['change'];
20
+ export function help() {
21
+ return renderHelp({
22
+ description: 'Records a change intent: which packages a change affects, the bump type for each, and a summary that becomes the changelog entry. The intent file is written to .changeset/ in the changesets format.',
23
+ usages: [
24
+ 'pnpm change [--bump <type>] [--summary <text>] [<pkg>...]',
25
+ 'pnpm change status',
26
+ ],
27
+ descriptionLists: [
28
+ {
29
+ title: 'Options',
30
+ list: [
31
+ {
32
+ description: `Bump type for the named packages: ${BUMP_TYPES.join(', ')}. "none" records an explicit decline — the change needs no release`,
33
+ name: '--bump <type>',
34
+ },
35
+ {
36
+ description: 'The summary for the changelog entry. Runs non-interactively when given together with package names',
37
+ name: '--summary <text>',
38
+ },
39
+ ],
40
+ },
41
+ ],
42
+ });
43
+ }
44
+ export async function handler(opts, params) {
45
+ const workspaceDir = opts.workspaceDir;
46
+ if (!workspaceDir) {
47
+ throw new PnpmError('WORKSPACE_ONLY', 'pnpm change is only supported in a workspace');
48
+ }
49
+ // Only the exact no-option invocation is the status form, so a package
50
+ // that happens to be named "status" stays recordable.
51
+ if (params.length === 1 && params[0] === 'status' && opts.bump == null && opts.summary == null) {
52
+ return renderStatus(workspaceDir, opts);
53
+ }
54
+ return recordChange(workspaceDir, opts, params);
55
+ }
56
+ async function recordChange(workspaceDir, opts, params) {
57
+ const releasable = getReleasableProjects(opts.allProjects ?? [], workspaceDir, opts.versioning);
58
+ if (releasable.length === 0) {
59
+ throw new PnpmError('VERSIONING_NO_PACKAGES', 'No releasable packages found in this workspace');
60
+ }
61
+ const releasableDirs = new Set(releasable.map((project) => project.dir));
62
+ const refs = indexProjectRefs(opts.allProjects ?? [], workspaceDir);
63
+ for (const ref of params) {
64
+ const dirs = refs.refToDirs(ref);
65
+ if (dirs.length > 1) {
66
+ throw new PnpmError('VERSIONING_AMBIGUOUS_PACKAGE', `${ref} matches multiple workspace projects: ${dirs.map((dir) => `./${dir}`).join(', ')}. Reference the project by directory instead.`);
67
+ }
68
+ if (dirs.length === 0 || !releasableDirs.has(dirs[0])) {
69
+ throw new PnpmError('VERSIONING_UNKNOWN_PACKAGE', `${ref} is not a releasable package of this workspace`);
70
+ }
71
+ }
72
+ if (opts.bump != null && !BUMP_TYPES.includes(opts.bump)) {
73
+ throw new PnpmError('VERSIONING_INVALID_BUMP', `Invalid bump type: ${opts.bump}. Expected one of ${BUMP_TYPES.join(', ')}`);
74
+ }
75
+ const pkgRefs = params.length > 0
76
+ ? params
77
+ : await promptForPackages(releasable, workspaceDir, opts);
78
+ const releases = opts.bump != null
79
+ ? Object.fromEntries(pkgRefs.map((ref) => [ref, opts.bump]))
80
+ : await promptBumpTypes(pkgRefs);
81
+ const summary = opts.summary ??
82
+ await input({ message: 'Summary of the change (becomes the changelog entry):', required: true });
83
+ const id = await writeChangeIntent(workspaceDir, { releases, summary });
84
+ return `Recorded change intent .changeset/${id}.md`;
85
+ }
86
+ /**
87
+ * The affected-packages picker, changesets-style: the packages whose
88
+ * directories the branch touched are grouped first (under a "changed
89
+ * packages" heading) and preselected, the rest listed below under "unchanged
90
+ * packages". A name shared by several projects is offered under its directory
91
+ * reference so the written intent stays unambiguous. Change detection is
92
+ * best-effort — outside a git repo, or when no base branch can be found, the
93
+ * list falls back to a flat, unselected picker.
94
+ */
95
+ async function promptForPackages(releasable, workspaceDir, opts) {
96
+ const changedDirs = await detectChangedDirs(releasable, workspaceDir, opts);
97
+ const label = (project) => project.ref === project.name ? project.name : `${project.name} (./${project.dir})`;
98
+ let choices;
99
+ if (changedDirs.size > 0) {
100
+ const changed = releasable.filter((project) => changedDirs.has(project.dir));
101
+ const unchanged = releasable.filter((project) => !changedDirs.has(project.dir));
102
+ choices = [
103
+ new Separator('changed packages'),
104
+ ...changed.map((project) => ({ value: project.ref, name: label(project), checked: true })),
105
+ ...(unchanged.length > 0 ? [new Separator('unchanged packages')] : []),
106
+ ...unchanged.map((project) => ({ value: project.ref, name: label(project) })),
107
+ ];
108
+ }
109
+ else {
110
+ choices = releasable.map((project) => ({ value: project.ref, name: label(project) }));
111
+ }
112
+ return checkbox({
113
+ message: 'Which packages does this change affect?',
114
+ choices,
115
+ required: true,
116
+ });
117
+ }
118
+ /**
119
+ * The workspace-relative directories the current branch changed, relative to
120
+ * the base branch, using the same detection behind `--filter="[<ref>]"`.
121
+ * Returns an empty set on any failure so the picker degrades to a flat list.
122
+ */
123
+ async function detectChangedDirs(releasable, workspaceDir, opts) {
124
+ const baseCommit = await detectBaseCommit(workspaceDir);
125
+ if (baseCommit == null)
126
+ return new Set();
127
+ try {
128
+ const projectDirs = (opts.allProjects ?? []).map((project) => project.rootDir);
129
+ const [changedRootDirs] = await getChangedProjects(projectDirs, baseCommit, {
130
+ workspaceDir,
131
+ testPattern: opts.testPattern,
132
+ changedFilesIgnorePattern: opts.changedFilesIgnorePattern,
133
+ });
134
+ const releasableDirs = new Set(releasable.map((project) => project.dir));
135
+ return new Set(changedRootDirs
136
+ .map((rootDir) => toProjectDir(workspaceDir, rootDir))
137
+ .filter((dir) => releasableDirs.has(dir)));
138
+ }
139
+ catch {
140
+ return new Set();
141
+ }
142
+ }
143
+ /** The merge-base of HEAD with the default branch, or `undefined`. */
144
+ async function detectBaseCommit(cwd) {
145
+ for (const branch of ['main', 'master']) {
146
+ try {
147
+ // eslint-disable-next-line no-await-in-loop
148
+ const { stdout } = await execa('git', ['merge-base', 'HEAD', branch], { cwd });
149
+ const commit = String(stdout).trim();
150
+ if (commit !== '')
151
+ return commit;
152
+ }
153
+ catch {
154
+ // Try the next candidate branch.
155
+ }
156
+ }
157
+ return undefined;
158
+ }
159
+ /**
160
+ * The changesets-style bump picker: ask which packages get a major bump, then
161
+ * which of the rest get a minor, and default whatever remains to patch. One
162
+ * multiselect per level reads far better than a per-package prompt when many
163
+ * packages are affected.
164
+ */
165
+ async function promptBumpTypes(pkgRefs) {
166
+ const bumpByRef = new Map();
167
+ let remaining = [...pkgRefs];
168
+ for (const bumpType of ['major', 'minor']) {
169
+ if (remaining.length === 0)
170
+ break;
171
+ // eslint-disable-next-line no-await-in-loop
172
+ const chosen = new Set(await checkbox({
173
+ message: `Which packages should have a ${bumpType} bump?`,
174
+ choices: remaining.map((ref) => ({ value: ref })),
175
+ }));
176
+ for (const ref of chosen)
177
+ bumpByRef.set(ref, bumpType);
178
+ remaining = remaining.filter((ref) => !chosen.has(ref));
179
+ }
180
+ for (const ref of remaining)
181
+ bumpByRef.set(ref, 'patch');
182
+ // Emit in the original selection order rather than grouped by bump level.
183
+ return Object.fromEntries(pkgRefs.map((ref) => [ref, bumpByRef.get(ref)]));
184
+ }
185
+ async function renderStatus(workspaceDir, opts) {
186
+ const intents = await readChangeIntents(workspaceDir);
187
+ const ledger = await readLedger(workspaceDir);
188
+ const baseArgs = {
189
+ workspaceDir,
190
+ projects: toWorkspaceProjects(opts.allProjects ?? []),
191
+ intents,
192
+ ledger,
193
+ versioning: opts.versioning,
194
+ };
195
+ const unpublishedDirs = await resolveUnpublishedDirs(assembleReleasePlan(baseArgs), opts);
196
+ const plan = assembleReleasePlan({ ...baseArgs, unpublishedDirs });
197
+ if (plan.releases.length === 0) {
198
+ return 'No pending changes.';
199
+ }
200
+ const consumedIds = new Set(plan.releases.flatMap((release) => release.intents.map((intent) => intent.id)));
201
+ let output = 'Pending change intents:\n';
202
+ for (const intent of intents.filter(({ id }) => consumedIds.has(id))) {
203
+ output += ` .changeset/${intent.id}.md\n`;
204
+ }
205
+ output += '\n';
206
+ output += renderReleasePlan(plan);
207
+ return output;
208
+ }
209
+ export function renderReleasePlan(plan) {
210
+ let output = 'Release plan:\n';
211
+ for (const release of plan.releases) {
212
+ output += ` ${release.name}: ${release.currentVersion} → ${release.newVersion} (${release.bumpType}, via ${release.causes.join('+')})\n`;
213
+ }
214
+ return output;
215
+ }
216
+ /**
217
+ * The projects a change intent may demand a release from: named, carrying a
218
+ * valid semver version, and not frozen by `versioning.ignore`. Matches the
219
+ * participant set of the release-plan assembler.
220
+ */
221
+ export function getReleasableProjects(allProjects, workspaceDir, versioning) {
222
+ const refs = indexProjectRefs(allProjects, workspaceDir);
223
+ const ignoredDirs = new Set((versioning?.ignore ?? []).flatMap((ref) => refs.refToDirs(ref)));
224
+ return allProjects
225
+ .filter(({ manifest }) => manifest.name != null &&
226
+ manifest.version != null &&
227
+ valid(manifest.version) != null)
228
+ .map((project) => ({ name: project.manifest.name, dir: toProjectDir(workspaceDir, project.rootDir) }))
229
+ .filter(({ dir }) => !ignoredDirs.has(dir))
230
+ .map(({ name, dir }) => ({
231
+ name,
232
+ dir,
233
+ ref: refs.nameToDirs(name).length > 1 ? `./${dir}` : name,
234
+ }))
235
+ .sort((left, right) => left.ref.localeCompare(right.ref));
236
+ }
237
+ export function toWorkspaceProjects(allProjects) {
238
+ return allProjects.map((project) => ({ rootDir: project.rootDir, manifest: project.manifest }));
239
+ }
240
+ export const change = {
241
+ handler,
242
+ help,
243
+ commandNames,
244
+ cliOptionsTypes,
245
+ rcOptionsTypes,
246
+ recursiveByDefault: true,
247
+ };
248
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,26 @@
1
+ import type { LockfileObject } from '@pnpm/lockfile.types';
2
+ import type { DependenciesField, PnpmSettings, Project, ProjectId, ProjectManifest } from '@pnpm/types';
3
+ export interface CreateDeployFilesOptions {
4
+ allProjects: Array<Pick<Project, 'manifest' | 'rootDirRealPath'>>;
5
+ deployDir: string;
6
+ include: {
7
+ [dependenciesField in DependenciesField]: boolean;
8
+ };
9
+ lockfile: LockfileObject;
10
+ lockfileDir: string;
11
+ patchedDependencies?: PnpmSettings['patchedDependencies'];
12
+ selectedProjectManifest: ProjectManifest;
13
+ projectId: ProjectId;
14
+ rootProjectManifestDir: string;
15
+ allowBuilds?: Record<string, boolean | string>;
16
+ }
17
+ export interface DeployWorkspaceManifest {
18
+ allowBuilds?: Record<string, boolean | string>;
19
+ patchedDependencies?: Record<string, string>;
20
+ }
21
+ export interface DeployFiles {
22
+ lockfile: LockfileObject;
23
+ manifest: ProjectManifest;
24
+ workspaceManifest?: DeployWorkspaceManifest;
25
+ }
26
+ export declare function createDeployFiles({ allProjects, deployDir, include, lockfile, lockfileDir, patchedDependencies, selectedProjectManifest, projectId, rootProjectManifestDir, allowBuilds, }: CreateDeployFilesOptions): DeployFiles;
@@ -0,0 +1,255 @@
1
+ import path from 'node:path';
2
+ import url from 'node:url';
3
+ import * as dp from '@pnpm/deps.path';
4
+ import normalizePath from 'normalize-path';
5
+ const DEPENDENCIES_FIELD = ['dependencies', 'devDependencies', 'optionalDependencies'];
6
+ export function createDeployFiles({ allProjects, deployDir, include, lockfile, lockfileDir, patchedDependencies, selectedProjectManifest, projectId, rootProjectManifestDir, allowBuilds, }) {
7
+ const deployedProjectRealPath = path.resolve(lockfileDir, projectId);
8
+ const inputSnapshot = lockfile.importers[projectId];
9
+ const targetSnapshot = {
10
+ ...inputSnapshot,
11
+ specifiers: {},
12
+ dependencies: {},
13
+ devDependencies: {},
14
+ optionalDependencies: {},
15
+ };
16
+ const targetPackageSnapshots = {};
17
+ for (const name in lockfile.packages) {
18
+ const inputDepPath = name;
19
+ const inputSnapshot = lockfile.packages[inputDepPath];
20
+ const resolveResult = resolveLinkOrFile(inputDepPath, {
21
+ lockfileDir,
22
+ projectRootDirRealPath: rootProjectManifestDir,
23
+ });
24
+ const outputDepPath = resolveResult
25
+ ? createFileUrlDepPath(resolveResult, allProjects)
26
+ : inputDepPath;
27
+ targetPackageSnapshots[outputDepPath] = convertPackageSnapshot(inputSnapshot, {
28
+ allProjects,
29
+ deployDir,
30
+ deployedProjectRealPath,
31
+ lockfileDir,
32
+ projectRootDirRealPath: rootProjectManifestDir,
33
+ });
34
+ }
35
+ for (const importerPath in lockfile.importers) {
36
+ if (importerPath === projectId)
37
+ continue;
38
+ const projectSnapshot = lockfile.importers[importerPath];
39
+ const projectRootDirRealPath = path.resolve(lockfileDir, importerPath);
40
+ const packageSnapshot = convertProjectSnapshotToPackageSnapshot(projectSnapshot, {
41
+ allProjects,
42
+ deployDir,
43
+ lockfileDir,
44
+ deployedProjectRealPath,
45
+ projectRootDirRealPath,
46
+ });
47
+ const depPath = createFileUrlDepPath({ resolvedPath: projectRootDirRealPath }, allProjects);
48
+ targetPackageSnapshots[depPath] = packageSnapshot;
49
+ }
50
+ for (const field of DEPENDENCIES_FIELD) {
51
+ const targetDependencies = targetSnapshot[field] ?? {};
52
+ const targetSpecifiers = targetSnapshot.specifiers;
53
+ const inputDependencies = inputSnapshot[field] ?? {};
54
+ for (const name in inputDependencies) {
55
+ const version = inputDependencies[name];
56
+ const resolveResult = resolveLinkOrFile(version, {
57
+ lockfileDir,
58
+ projectRootDirRealPath: path.resolve(lockfileDir, projectId),
59
+ });
60
+ if (!resolveResult) {
61
+ targetSpecifiers[name] = targetDependencies[name] = version;
62
+ continue;
63
+ }
64
+ resolveResult.packageName ??= name;
65
+ targetSpecifiers[name] = targetDependencies[name] =
66
+ resolveResult.resolvedPath === deployedProjectRealPath ? 'link:.' : createFileUrlDepPath(resolveResult, allProjects);
67
+ }
68
+ }
69
+ const deployPackageSnapshots = filterDeployPackageSnapshots(targetSnapshot, targetPackageSnapshots, include);
70
+ const result = {
71
+ lockfile: {
72
+ ...lockfile,
73
+ // The deployed manifest contains concrete versions, and catalogs are not copied to the target.
74
+ catalogs: undefined,
75
+ patchedDependencies: undefined,
76
+ overrides: undefined, // the effects of the overrides should already be part of the package snapshots
77
+ packageExtensionsChecksum: undefined, // the effects of the package extensions should already be part of the package snapshots
78
+ pnpmfileChecksum: undefined, // the effects of the pnpmfile should already be part of the package snapshots
79
+ settings: {
80
+ ...lockfile.settings,
81
+ injectWorkspacePackages: undefined, // the effects of injecting workspace packages should already be part of the lockfile
82
+ },
83
+ importers: {
84
+ ['.']: targetSnapshot,
85
+ },
86
+ packages: deployPackageSnapshots,
87
+ },
88
+ manifest: {
89
+ ...selectedProjectManifest,
90
+ dependencies: targetSnapshot.dependencies,
91
+ devDependencies: targetSnapshot.devDependencies,
92
+ optionalDependencies: targetSnapshot.optionalDependencies,
93
+ },
94
+ };
95
+ if (lockfile.patchedDependencies && patchedDependencies) {
96
+ result.lockfile.patchedDependencies = { ...lockfile.patchedDependencies };
97
+ const deployManifestPatchedDeps = {};
98
+ for (const name in patchedDependencies) {
99
+ const absolutePath = patchedDependencies[name];
100
+ const relativePath = normalizePath(path.relative(deployDir, absolutePath));
101
+ deployManifestPatchedDeps[name] = relativePath;
102
+ }
103
+ result.workspaceManifest = {
104
+ ...result.workspaceManifest,
105
+ patchedDependencies: deployManifestPatchedDeps,
106
+ };
107
+ }
108
+ if (allowBuilds) {
109
+ result.workspaceManifest = {
110
+ ...result.workspaceManifest,
111
+ allowBuilds,
112
+ };
113
+ }
114
+ return result;
115
+ }
116
+ function filterDeployPackageSnapshots(importer, packages, include) {
117
+ const queue = [];
118
+ const enqueue = (dependencies) => {
119
+ for (const [alias, reference] of Object.entries(dependencies ?? {})) {
120
+ const depPath = dp.refToRelative(reference, alias);
121
+ if (depPath != null && packages[depPath] != null)
122
+ queue.push(depPath);
123
+ }
124
+ };
125
+ if (include.dependencies)
126
+ enqueue(importer.dependencies);
127
+ if (include.devDependencies)
128
+ enqueue(importer.devDependencies);
129
+ if (include.optionalDependencies)
130
+ enqueue(importer.optionalDependencies);
131
+ const reachable = new Set();
132
+ let head = 0;
133
+ while (head < queue.length) {
134
+ const depPath = queue[head++];
135
+ if (reachable.has(depPath))
136
+ continue;
137
+ reachable.add(depPath);
138
+ const snapshot = packages[depPath];
139
+ if (snapshot == null)
140
+ continue;
141
+ enqueue(snapshot.dependencies);
142
+ if (include.optionalDependencies)
143
+ enqueue(snapshot.optionalDependencies);
144
+ }
145
+ return Object.fromEntries(Array.from(reachable, (depPath) => [depPath, packages[depPath]]));
146
+ }
147
+ function convertPackageSnapshot(inputSnapshot, opts) {
148
+ const inputResolution = inputSnapshot.resolution;
149
+ let outputResolution;
150
+ if ('integrity' in inputResolution) {
151
+ outputResolution = inputResolution;
152
+ }
153
+ else if ('tarball' in inputResolution && typeof inputResolution.tarball === 'string') {
154
+ outputResolution = { ...inputResolution };
155
+ if (inputResolution.tarball.startsWith('file:')) {
156
+ const inputPath = inputResolution.tarball.slice('file:'.length);
157
+ const resolvedPath = path.resolve(opts.lockfileDir, inputPath);
158
+ const outputPath = normalizePath(path.relative(opts.deployDir, resolvedPath));
159
+ outputResolution.tarball = `file:${outputPath}`;
160
+ if ('path' in inputResolution && typeof inputResolution.path === 'string') {
161
+ outputResolution.path = outputPath;
162
+ }
163
+ }
164
+ }
165
+ else if (inputResolution.type === 'directory') {
166
+ const dirResolution = inputResolution;
167
+ const resolvedPath = path.resolve(opts.lockfileDir, dirResolution.directory);
168
+ const directory = normalizePath(path.relative(opts.deployDir, resolvedPath));
169
+ outputResolution = { ...dirResolution, directory };
170
+ }
171
+ else if (inputResolution.type === 'git' || inputResolution.type === 'variations') {
172
+ outputResolution = inputResolution;
173
+ }
174
+ else if (inputResolution.type && typeof inputResolution.type === 'string') {
175
+ // Custom resolution type - pass through as-is
176
+ outputResolution = inputResolution;
177
+ }
178
+ else {
179
+ throw new Error(`Unknown resolution type: ${JSON.stringify(inputResolution)}`);
180
+ }
181
+ return {
182
+ ...inputSnapshot,
183
+ resolution: outputResolution,
184
+ dependencies: convertResolvedDependencies(inputSnapshot.dependencies, opts),
185
+ optionalDependencies: convertResolvedDependencies(inputSnapshot.optionalDependencies, opts),
186
+ };
187
+ }
188
+ function convertProjectSnapshotToPackageSnapshot(projectSnapshot, opts) {
189
+ const resolution = {
190
+ type: 'directory',
191
+ directory: normalizePath(path.relative(opts.deployDir, opts.projectRootDirRealPath)),
192
+ };
193
+ const dependencies = convertResolvedDependencies(projectSnapshot.dependencies, opts);
194
+ const optionalDependencies = convertResolvedDependencies(projectSnapshot.optionalDependencies, opts);
195
+ return {
196
+ dependencies,
197
+ optionalDependencies,
198
+ resolution,
199
+ };
200
+ }
201
+ function convertResolvedDependencies(input, opts) {
202
+ if (!input)
203
+ return undefined;
204
+ const output = {};
205
+ for (const key in input) {
206
+ const version = input[key];
207
+ const resolveResult = resolveLinkOrFile(version, opts);
208
+ if (!resolveResult) {
209
+ output[key] = version;
210
+ continue;
211
+ }
212
+ if (resolveResult.resolvedPath === opts.deployedProjectRealPath) {
213
+ output[key] = 'link:.'; // the path is relative to the lockfile dir, which means '.' would reference the deploy dir
214
+ continue;
215
+ }
216
+ resolveResult.packageName ??= key;
217
+ output[key] = createFileUrlDepPath(resolveResult, opts.allProjects);
218
+ }
219
+ return output;
220
+ }
221
+ function resolveLinkOrFile(pkgVer, opts) {
222
+ const { lockfileDir, projectRootDirRealPath } = opts;
223
+ function resolveScheme(scheme, base) {
224
+ if (!pkgVer.startsWith(scheme))
225
+ return undefined;
226
+ const { id, peerDepGraphHash: suffix } = dp.parseDepPath(pkgVer.slice(scheme.length));
227
+ const resolvedPath = path.resolve(base, id);
228
+ return { scheme, resolvedPath, suffix };
229
+ }
230
+ const resolveSchemeResult = resolveScheme('file:', lockfileDir) ?? resolveScheme('link:', projectRootDirRealPath);
231
+ if (resolveSchemeResult)
232
+ return resolveSchemeResult;
233
+ const { name, nonSemverVersion, patchHash, peerDepGraphHash, version } = dp.parse(pkgVer);
234
+ if (!nonSemverVersion)
235
+ return undefined;
236
+ if (version) {
237
+ throw new Error(`Something goes wrong, version should be undefined but isn't: ${version}`);
238
+ }
239
+ const parseResult = resolveLinkOrFile(nonSemverVersion, opts);
240
+ if (!parseResult)
241
+ return undefined;
242
+ if (parseResult.suffix) {
243
+ throw new Error(`Something goes wrong, suffix should be undefined but isn't: ${parseResult.suffix}`);
244
+ }
245
+ parseResult.suffix = `${patchHash ?? ''}${peerDepGraphHash ?? ''}`;
246
+ parseResult.packageName = name;
247
+ return parseResult;
248
+ }
249
+ function createFileUrlDepPath({ resolvedPath, suffix, packageName }, allProjects) {
250
+ const depFileUrl = url.pathToFileURL(resolvedPath).toString();
251
+ const project = allProjects.find(project => project.rootDirRealPath === resolvedPath);
252
+ const name = project?.manifest.name ?? packageName ?? path.basename(resolvedPath);
253
+ return `${name}@${depFileUrl}${suffix ?? ''}`;
254
+ }
255
+ //# sourceMappingURL=createDeployFiles.js.map
@@ -0,0 +1,12 @@
1
+ import { type Config } from '@pnpm/config.reader';
2
+ import { install } from '@pnpm/installing.commands';
3
+ export declare const shorthands: {
4
+ legacy: string[];
5
+ };
6
+ export declare function rcOptionsTypes(): Record<string, unknown>;
7
+ export declare function cliOptionsTypes(): Record<string, unknown>;
8
+ export declare const commandNames: string[];
9
+ export declare const overridableByScript = true;
10
+ export declare function help(): string;
11
+ export type DeployOptions = Omit<install.InstallCommandOptions, 'useLockfile'> & Pick<Config, 'allowBuilds' | 'forceLegacyDeploy'>;
12
+ export declare function handler(opts: DeployOptions, params: string[]): Promise<void>;