@pnpm/releasing.exportable-manifest 1100.3.2 → 1100.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # @pnpm/exportable-manifest
2
2
 
3
+ ## 1100.3.4
4
+
5
+ ### Patch Changes
6
+
7
+ - `pnpm install` now works in StackBlitz WebContainers on projects without a lockfile. It used to fail there with `ENOENT ... pnpm-lock.yaml`, because pnpm did not recognize the errors that WebContainers return from asynchronous file system calls [#15649](https://github.com/pnpm/pnpm/issues/15649).
8
+
9
+ - Updated dependencies:
10
+ - @pnpm/catalogs.resolver@1100.1.1
11
+ - @pnpm/error@1100.2.1
12
+ - @pnpm/resolving.jsr-specifier-parser@1100.0.9
13
+ - @pnpm/workspace.project-manifest-reader@1100.1.1
14
+
15
+ ## 1100.3.3
16
+
17
+ ### Patch Changes
18
+
19
+ - The `publish` command now resolves `workspace:` dependencies from workspace manifests when `node_modules` is not installed. Previously, publishing without `node_modules` failed with `ERR_PNPM_CANNOT_RESOLVE_WORKSPACE_PROTOCOL`. pnpm/pnpm#6567
20
+
21
+ - `make-dedicated-lockfile` no longer removes fields such as `main` and `types` from the `publishConfig` of the project's `package.json`.
22
+
23
+ - `pnpm publish` and `pnpm pack` now report a missing `version` or `name` field on a workspace dependency. Previously, pnpm reported that the dependency was not installed [#4164](https://github.com/pnpm/pnpm/issues/4164).
24
+
25
+ - Updated dependencies:
26
+ - @pnpm/bins.resolver@1100.0.17
27
+ - @pnpm/error@1100.2.0
28
+ - @pnpm/resolving.jsr-specifier-parser@1100.0.8
29
+ - @pnpm/types@1102.1.1
30
+ - @pnpm/workspace.project-manifest-reader@1100.1.0
31
+
3
32
  ## 1100.3.2
4
33
 
5
34
  ### Patch Changes
package/lib/index.d.ts CHANGED
@@ -3,12 +3,17 @@ import type { Hooks } from '@pnpm/hooks.pnpmfile';
3
3
  import type { ProjectManifest } from '@pnpm/types';
4
4
  import { type ExportedManifest } from './transform/index.js';
5
5
  export { type ExportedManifest };
6
+ export type WorkspacePackageLookup = Array<{
7
+ manifest: ProjectManifest;
8
+ rootDir?: string;
9
+ }> | Map<string, unknown> | Record<string, unknown> | ((depName: string) => ProjectManifest | undefined);
6
10
  export interface MakePublishManifestOptions {
7
11
  catalogs: Catalogs;
8
12
  hooks?: Hooks;
9
13
  modulesDir?: string;
10
14
  skipManifestObfuscation?: boolean;
11
15
  embedReadme?: boolean;
16
+ workspacePackages?: WorkspacePackageLookup;
12
17
  }
13
18
  export declare function createExportableManifest(dir: string, originalManifest: ProjectManifest, opts: MakePublishManifestOptions): Promise<ExportedManifest>;
14
19
  export declare function readReadmeFile(projectDir: string): Promise<string | undefined>;
@@ -16,8 +21,10 @@ export type PublishDependencyConverter = (depName: string, depSpec: string, cont
16
21
  export interface PublishDependencyConverterContext {
17
22
  dir: string;
18
23
  modulesDir?: string;
24
+ workspacePackages?: (depName: string) => ProjectManifest | undefined;
19
25
  }
20
26
  export interface MakePublishDependenciesOpts {
21
27
  readonly modulesDir?: string;
22
28
  readonly convertDependencyForPublish: PublishDependencyConverter;
29
+ readonly workspacePackages?: (depName: string) => ProjectManifest | undefined;
23
30
  }
package/lib/index.js CHANGED
@@ -1,8 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import util from 'node:util';
4
3
  import { resolveFromCatalog } from '@pnpm/catalogs.resolver';
5
- import { PnpmError } from '@pnpm/error';
4
+ import { isError, PnpmError } from '@pnpm/error';
6
5
  import { parseJsrSpecifier } from '@pnpm/resolving.jsr-specifier-parser';
7
6
  import { tryReadProjectManifest } from '@pnpm/workspace.project-manifest-reader';
8
7
  import { WorkspaceSpec } from '@pnpm/workspace.spec-parser';
@@ -31,11 +30,13 @@ export async function createExportableManifest(dir, originalManifest, opts) {
31
30
  }
32
31
  const catalogResolver = resolveFromCatalog.bind(null, opts.catalogs);
33
32
  const replaceCatalogProtocol = resolveCatalogProtocol.bind(null, catalogResolver);
33
+ const getWorkspaceManifest = buildWorkspaceManifestGetter(opts.workspacePackages);
34
34
  const convertDependencyForPublish = combineConverters(replaceCatalogProtocol, replaceWorkspaceProtocol, replaceJsrProtocol);
35
35
  await Promise.all(['dependencies', 'devDependencies', 'optionalDependencies'].map(async (depsField) => {
36
36
  const deps = await makePublishDependencies(dir, originalManifest[depsField], {
37
37
  modulesDir: opts?.modulesDir,
38
38
  convertDependencyForPublish,
39
+ workspacePackages: getWorkspaceManifest,
39
40
  });
40
41
  if (deps != null) {
41
42
  publishManifest[depsField] = deps;
@@ -47,6 +48,7 @@ export async function createExportableManifest(dir, originalManifest, opts) {
47
48
  publishManifest.peerDependencies = await makePublishDependencies(dir, peerDependencies, {
48
49
  modulesDir: opts?.modulesDir,
49
50
  convertDependencyForPublish: convertPeersForPublish,
51
+ workspacePackages: getWorkspaceManifest,
50
52
  });
51
53
  }
52
54
  overridePublishConfig(publishManifest);
@@ -81,7 +83,7 @@ export async function readReadmeFile(projectDir) {
81
83
  }
82
84
  catch (err) {
83
85
  // ELOOP: the entry is a symlink after all (a concurrent swap) — skip it, as the isFile() check intended.
84
- if (util.types.isNativeError(err) && 'code' in err && err.code === 'ELOOP')
86
+ if (isError(err) && 'code' in err && err.code === 'ELOOP')
85
87
  return undefined;
86
88
  throw err;
87
89
  }
@@ -99,19 +101,91 @@ function combineConverters(...converters) {
99
101
  return bareSpecifier;
100
102
  };
101
103
  }
102
- async function makePublishDependencies(dir, dependencies, { modulesDir, convertDependencyForPublish }) {
104
+ async function makePublishDependencies(dir, dependencies, { modulesDir, convertDependencyForPublish, workspacePackages }) {
103
105
  if (dependencies == null)
104
106
  return dependencies;
105
- const publishDependencies = await Promise.all(Object.entries(dependencies).map(async ([depName, depSpec]) => [depName, await convertDependencyForPublish(depName, depSpec, { dir, modulesDir })]));
107
+ const publishDependencies = await Promise.all(Object.entries(dependencies).map(async ([depName, depSpec]) => [depName, await convertDependencyForPublish(depName, depSpec, { dir, modulesDir, workspacePackages })]));
106
108
  return Object.fromEntries(publishDependencies);
107
109
  }
108
- async function readAndCheckManifest(depName, dependencyDir) {
109
- const { manifest } = await tryReadProjectManifest(dependencyDir);
110
- if (!manifest?.name || !manifest?.version) {
110
+ function extractManifest(val) {
111
+ if (!val || typeof val !== 'object')
112
+ return undefined;
113
+ if ('manifest' in val && val.manifest && typeof val.manifest === 'object') {
114
+ return val.manifest;
115
+ }
116
+ if ('package' in val && val.package && typeof val.package === 'object' && 'manifest' in val.package && val.package.manifest && typeof val.package.manifest === 'object') {
117
+ return val.package.manifest;
118
+ }
119
+ if ('name' in val && typeof val.name === 'string') {
120
+ return val;
121
+ }
122
+ return undefined;
123
+ }
124
+ function buildWorkspaceManifestGetter(workspacePackages) {
125
+ if (!workspacePackages)
126
+ return undefined;
127
+ if (typeof workspacePackages === 'function') {
128
+ return workspacePackages;
129
+ }
130
+ const byName = new Map();
131
+ const addManifest = (val) => {
132
+ const manifest = extractManifest(val);
133
+ if (!manifest?.name)
134
+ return;
135
+ const existing = byName.get(manifest.name);
136
+ if (!existing || (!existing.version && manifest.version)) {
137
+ byName.set(manifest.name, manifest);
138
+ }
139
+ };
140
+ if (Array.isArray(workspacePackages)) {
141
+ for (const pkg of workspacePackages) {
142
+ addManifest(pkg);
143
+ }
144
+ }
145
+ else if (workspacePackages instanceof Map) {
146
+ for (const val of workspacePackages.values()) {
147
+ if (val instanceof Map) {
148
+ for (const subVal of val.values()) {
149
+ addManifest(subVal);
150
+ }
151
+ }
152
+ else {
153
+ addManifest(val);
154
+ }
155
+ }
156
+ }
157
+ else if (typeof workspacePackages === 'object') {
158
+ for (const val of Object.values(workspacePackages)) {
159
+ addManifest(val);
160
+ }
161
+ }
162
+ return (depName) => byName.get(depName);
163
+ }
164
+ async function readAndCheckManifest(depName, dependencyDir, getWorkspaceManifest, targetPkgName) {
165
+ const { manifest: dirManifest } = await tryReadProjectManifest(dependencyDir);
166
+ if (dirManifest?.name && dirManifest?.version) {
167
+ return dirManifest;
168
+ }
169
+ const lookupName = targetPkgName ?? depName;
170
+ const workspaceManifest = getWorkspaceManifest?.(lookupName);
171
+ if (workspaceManifest?.name && workspaceManifest?.version) {
172
+ return workspaceManifest;
173
+ }
174
+ const found = dirManifest?.name || dirManifest?.version
175
+ ? dirManifest
176
+ : workspaceManifest?.name || workspaceManifest?.version
177
+ ? workspaceManifest
178
+ : dirManifest ?? workspaceManifest;
179
+ if (found?.name && !found.version) {
180
+ throw new PnpmError('CANNOT_RESOLVE_WORKSPACE_PROTOCOL', `Cannot resolve workspace protocol of dependency "${depName}" ` +
181
+ 'because its package.json has no "version" field.', { hint: `Add a "version" field to the package.json of "${found.name}".` });
182
+ }
183
+ if (found) {
111
184
  throw new PnpmError('CANNOT_RESOLVE_WORKSPACE_PROTOCOL', `Cannot resolve workspace protocol of dependency "${depName}" ` +
112
- 'because this dependency is not installed. Try running "pnpm install".');
185
+ 'because its package.json has no "name" field.');
113
186
  }
114
- return manifest;
187
+ throw new PnpmError('CANNOT_RESOLVE_WORKSPACE_PROTOCOL', `Cannot resolve workspace protocol of dependency "${depName}" ` +
188
+ 'because this dependency is not installed. Try running "pnpm install".');
115
189
  }
116
190
  function resolveCatalogProtocol(catalogResolver, alias, bareSpecifier) {
117
191
  const result = catalogResolver({ alias, bareSpecifier });
@@ -121,7 +195,7 @@ function resolveCatalogProtocol(catalogResolver, alias, bareSpecifier) {
121
195
  case 'misconfiguration': throw result.error;
122
196
  }
123
197
  }
124
- async function replaceWorkspaceProtocol(depName, depSpec, { dir, modulesDir }) {
198
+ async function replaceWorkspaceProtocol(depName, depSpec, { dir, modulesDir, workspacePackages }) {
125
199
  if (!depSpec.startsWith('workspace:')) {
126
200
  return depSpec;
127
201
  }
@@ -129,7 +203,8 @@ async function replaceWorkspaceProtocol(depName, depSpec, { dir, modulesDir }) {
129
203
  const versionAliasSpecParts = /^workspace:(?:(.+)@)?([\^~*])?$/.exec(depSpec);
130
204
  if (versionAliasSpecParts != null) {
131
205
  modulesDir = modulesDir ?? path.join(dir, 'node_modules');
132
- const manifest = await readAndCheckManifest(depName, path.join(modulesDir, depName));
206
+ const targetPkgName = versionAliasSpecParts[1];
207
+ const manifest = await readAndCheckManifest(depName, path.join(modulesDir, depName), workspacePackages, targetPkgName);
133
208
  const specifierSuffix = versionAliasSpecParts[2];
134
209
  const semverRangeToken = specifierSuffix === '^' || specifierSuffix === '~' ? specifierSuffix : '';
135
210
  if (depName !== manifest.name) {
@@ -138,7 +213,7 @@ async function replaceWorkspaceProtocol(depName, depSpec, { dir, modulesDir }) {
138
213
  return `${semverRangeToken}${manifest.version}`;
139
214
  }
140
215
  if (depSpec.startsWith('workspace:./') || depSpec.startsWith('workspace:../')) {
141
- const manifest = await readAndCheckManifest(depName, path.join(dir, depSpec.slice(10)));
216
+ const manifest = await readAndCheckManifest(depName, path.join(dir, depSpec.slice(10)), workspacePackages);
142
217
  if (manifest.name === depName)
143
218
  return `${manifest.version}`;
144
219
  return `npm:${manifest.name}@${manifest.version}`;
@@ -149,7 +224,7 @@ async function replaceWorkspaceProtocol(depName, depSpec, { dir, modulesDir }) {
149
224
  }
150
225
  return depSpec;
151
226
  }
152
- async function replaceWorkspaceProtocolPeerDependency(depName, depSpec, { dir, modulesDir }) {
227
+ async function replaceWorkspaceProtocolPeerDependency(depName, depSpec, { dir, modulesDir, workspacePackages }) {
153
228
  if (!depSpec.includes('workspace:')) {
154
229
  return depSpec;
155
230
  }
@@ -161,7 +236,7 @@ async function replaceWorkspaceProtocolPeerDependency(depName, depSpec, { dir, m
161
236
  return `npm:${workspaceSpec.alias}@${version}`;
162
237
  }
163
238
  if (workspaceSpec?.version.startsWith('./') || workspaceSpec?.version.startsWith('../')) {
164
- return replaceWorkspaceProtocol(depName, depSpec, { dir, modulesDir });
239
+ return replaceWorkspaceProtocol(depName, depSpec, { dir, modulesDir, workspacePackages });
165
240
  }
166
241
  // Dependencies with bare "*", "^", "~",">=",">","<=", "<", version
167
242
  const workspaceSemverRegex = /workspace:([\^~*]|>=|>|<=|<)?((\d+|[xX*])(\.(\d+|[xX*])){0,2})?/;
@@ -172,7 +247,7 @@ async function replaceWorkspaceProtocolPeerDependency(depName, depSpec, { dir, m
172
247
  return depSpec.replace('workspace:', '');
173
248
  }
174
249
  modulesDir = modulesDir ?? path.join(dir, 'node_modules');
175
- const manifest = await readAndCheckManifest(depName, path.join(modulesDir, depName));
250
+ const manifest = await readAndCheckManifest(depName, path.join(modulesDir, depName), workspacePackages);
176
251
  const semverRangeToken = semverRangGroup !== '*' ? semverRangGroup : '';
177
252
  return depSpec.replace(workspaceSemverRegex, `${semverRangeToken}${manifest.version}`);
178
253
  }
@@ -30,9 +30,9 @@ const PUBLISH_CONFIG_WHITELIST = new Set([
30
30
  'typesVersions',
31
31
  ]);
32
32
  export function overridePublishConfig(publishManifest) {
33
- const { publishConfig } = publishManifest;
34
- if (!publishConfig)
33
+ if (!publishManifest.publishConfig)
35
34
  return;
35
+ const publishConfig = { ...publishManifest.publishConfig };
36
36
  for (const key in publishConfig) {
37
37
  if (!PUBLISH_CONFIG_WHITELIST.has(key))
38
38
  continue;
@@ -43,5 +43,8 @@ export function overridePublishConfig(publishManifest) {
43
43
  if (isEmpty(publishConfig)) {
44
44
  delete publishManifest.publishConfig;
45
45
  }
46
+ else {
47
+ publishManifest.publishConfig = publishConfig;
48
+ }
46
49
  }
47
50
  //# sourceMappingURL=overridePublishConfig.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/releasing.exportable-manifest",
3
- "version": "1100.3.2",
3
+ "version": "1100.3.4",
4
4
  "description": "Creates an exportable manifest",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -28,22 +28,22 @@
28
28
  ],
29
29
  "dependencies": {
30
30
  "@npm/types": "^2.1.0",
31
- "@pnpm/bins.resolver": "1100.0.16",
32
- "@pnpm/catalogs.resolver": "1100.1.0",
33
- "@pnpm/error": "1100.1.4",
34
- "@pnpm/resolving.jsr-specifier-parser": "1100.0.7",
35
- "@pnpm/types": "1102.1.0",
36
- "@pnpm/workspace.project-manifest-reader": "1100.0.29",
31
+ "@pnpm/bins.resolver": "1100.0.17",
32
+ "@pnpm/catalogs.resolver": "1100.1.1",
33
+ "@pnpm/error": "1100.2.1",
34
+ "@pnpm/resolving.jsr-specifier-parser": "1100.0.9",
35
+ "@pnpm/types": "1102.1.1",
36
+ "@pnpm/workspace.project-manifest-reader": "1100.1.1",
37
37
  "@pnpm/workspace.spec-parser": "1100.0.1",
38
38
  "ramda": "npm:@pnpm/ramda@0.28.1"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@jest/globals": "30.4.1",
42
- "@pnpm/catalogs.config": "1100.0.7",
42
+ "@pnpm/catalogs.config": "1100.0.9",
43
43
  "@pnpm/catalogs.types": "1100.0.1",
44
- "@pnpm/hooks.pnpmfile": "1100.0.32",
45
- "@pnpm/prepare": "1100.0.31",
46
- "@pnpm/releasing.exportable-manifest": "1100.3.2",
44
+ "@pnpm/hooks.pnpmfile": "1100.0.34",
45
+ "@pnpm/prepare": "1100.0.33",
46
+ "@pnpm/releasing.exportable-manifest": "1100.3.4",
47
47
  "@types/cross-spawn": "^6.0.6",
48
48
  "@types/ramda": "0.32.0",
49
49
  "cross-spawn": "^7.0.6",