@pnpm/hooks.pnpmfile 1100.0.21 → 1100.0.23

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,31 @@
1
1
  # @pnpm/pnpmfile
2
2
 
3
+ ## 1100.0.23
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies:
8
+ - @pnpm/core-loggers@1100.3.0
9
+ - @pnpm/hooks.types@1100.2.4
10
+ - @pnpm/lockfile.types@1100.0.17
11
+ - @pnpm/store.controller-types@1100.1.11
12
+ - @pnpm/types@1101.7.0
13
+
14
+ ## 1100.0.22
15
+
16
+ ### Patch Changes
17
+
18
+ - 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).
19
+
20
+ - Updated dependencies:
21
+ - @pnpm/core-loggers@1100.2.5
22
+ - @pnpm/crypto.hash@1100.0.2
23
+ - @pnpm/error@1100.1.0
24
+ - @pnpm/hooks.types@1100.2.3
25
+ - @pnpm/lockfile.types@1100.0.16
26
+ - @pnpm/store.controller-types@1100.1.10
27
+ - @pnpm/types@1101.6.0
28
+
3
29
  ## 1100.0.21
4
30
 
5
31
  ### Patch Changes
package/lib/Hooks.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import type { Log } from '@pnpm/core-loggers';
2
+ import type { PreResolutionHook } from '@pnpm/hooks.types';
3
+ import type { LockfileObject } from '@pnpm/lockfile.types';
4
+ import type { ImportIndexedPackageAsync } from '@pnpm/store.controller-types';
5
+ export interface HookContext {
6
+ log: (message: string) => void;
7
+ }
8
+ export interface Hooks {
9
+ readPackage?: (pkg: any, context: HookContext) => any;
10
+ beforePacking?: (pkg: any, dir: string, context: HookContext) => any;
11
+ preResolution?: PreResolutionHook;
12
+ afterAllResolved?: (lockfile: LockfileObject, context: HookContext) => LockfileObject | Promise<LockfileObject>;
13
+ filterLog?: (log: Log) => boolean;
14
+ importPackage?: ImportIndexedPackageAsync;
15
+ updateConfig?: (config: any) => any;
16
+ }
package/lib/Hooks.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Hooks.js.map
package/lib/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import type { CookedHooks } from './requireHooks.js';
2
+ export type { HookContext } from './Hooks.js';
3
+ export { requireHooks } from './requireHooks.js';
4
+ export { BadReadPackageHookError } from './requirePnpmfile.js';
5
+ export type Hooks = CookedHooks;
@@ -0,0 +1,30 @@
1
+ import type { CustomFetcher, CustomResolver, PreResolutionHookContext } from '@pnpm/hooks.types';
2
+ import type { LockfileObject } from '@pnpm/lockfile.types';
3
+ import type { ImportIndexedPackageAsync } from '@pnpm/store.controller-types';
4
+ import type { BeforePackingHook, ReadPackageHook } from '@pnpm/types';
5
+ import type { Hooks } from './Hooks.js';
6
+ import { type Finders } from './requirePnpmfile.js';
7
+ type Cook<T extends (...args: any[]) => any> = (arg: Parameters<T>[0], ...otherArgs: any[]) => ReturnType<T>;
8
+ export interface CookedHooks {
9
+ readPackage?: ReadPackageHook[];
10
+ beforePacking?: BeforePackingHook[];
11
+ preResolution?: Array<(ctx: PreResolutionHookContext) => Promise<void>>;
12
+ afterAllResolved?: Array<(lockfile: LockfileObject) => LockfileObject | Promise<LockfileObject>>;
13
+ filterLog?: Array<Cook<Required<Hooks>['filterLog']>>;
14
+ updateConfig?: Array<Cook<Required<Hooks>['updateConfig']>>;
15
+ importPackage?: ImportIndexedPackageAsync;
16
+ customResolvers?: CustomResolver[];
17
+ customFetchers?: CustomFetcher[];
18
+ calculatePnpmfileChecksum?: () => Promise<string>;
19
+ }
20
+ export interface RequireHooksResult {
21
+ hooks: CookedHooks;
22
+ finders: Finders;
23
+ resolvedPnpmfilePaths: string[];
24
+ }
25
+ export declare function requireHooks(prefix: string, opts: {
26
+ globalPnpmfile?: string;
27
+ pnpmfiles?: string[];
28
+ tryLoadDefaultPnpmfile?: boolean;
29
+ }): Promise<RequireHooksResult>;
30
+ export {};
@@ -0,0 +1,189 @@
1
+ import { hookLogger } from '@pnpm/core-loggers';
2
+ import { createHashFromMultipleFiles } from '@pnpm/crypto.hash';
3
+ import { PnpmError } from '@pnpm/error';
4
+ import { pathAbsolute } from 'path-absolute';
5
+ import { requirePnpmfile } from './requirePnpmfile.js';
6
+ export async function requireHooks(prefix, opts) {
7
+ const pnpmfiles = [];
8
+ if (opts.globalPnpmfile) {
9
+ pnpmfiles.push({
10
+ path: opts.globalPnpmfile,
11
+ includeInChecksum: false,
12
+ });
13
+ }
14
+ const entries = [];
15
+ const loadedFiles = [];
16
+ if (opts.tryLoadDefaultPnpmfile) {
17
+ // Prefer .pnpmfile.mjs over .pnpmfile.cjs. Only load one.
18
+ const mjsPath = pathAbsolute('.pnpmfile.mjs', prefix);
19
+ const mjsResult = await requirePnpmfile(mjsPath, prefix);
20
+ if (mjsResult != null) {
21
+ loadedFiles.push(mjsPath);
22
+ entries.push({
23
+ file: mjsPath,
24
+ includeInChecksum: true,
25
+ hooks: mjsResult.pnpmfileModule?.hooks,
26
+ finders: mjsResult.pnpmfileModule?.finders,
27
+ resolvers: mjsResult.pnpmfileModule?.resolvers,
28
+ fetchers: mjsResult.pnpmfileModule?.fetchers,
29
+ });
30
+ }
31
+ else {
32
+ pnpmfiles.push({
33
+ path: '.pnpmfile.cjs',
34
+ includeInChecksum: true,
35
+ optional: true,
36
+ });
37
+ }
38
+ }
39
+ if (opts.pnpmfiles) {
40
+ for (const pnpmfile of opts.pnpmfiles) {
41
+ pnpmfiles.push({
42
+ path: pnpmfile,
43
+ includeInChecksum: true,
44
+ });
45
+ }
46
+ }
47
+ await Promise.all(pnpmfiles.map(async ({ path, includeInChecksum, optional }) => {
48
+ const file = pathAbsolute(path, prefix);
49
+ if (!loadedFiles.includes(file)) {
50
+ loadedFiles.push(file);
51
+ const requirePnpmfileResult = await requirePnpmfile(file, prefix);
52
+ if (requirePnpmfileResult != null) {
53
+ entries.push({
54
+ file,
55
+ includeInChecksum,
56
+ hooks: requirePnpmfileResult.pnpmfileModule?.hooks,
57
+ finders: requirePnpmfileResult.pnpmfileModule?.finders,
58
+ resolvers: requirePnpmfileResult.pnpmfileModule?.resolvers,
59
+ fetchers: requirePnpmfileResult.pnpmfileModule?.fetchers,
60
+ });
61
+ }
62
+ else if (!optional) {
63
+ throw new PnpmError('PNPMFILE_NOT_FOUND', `pnpmfile at "${file}" is not found`);
64
+ }
65
+ }
66
+ }));
67
+ const mergedFinders = {};
68
+ const cookedHooks = {
69
+ readPackage: [],
70
+ beforePacking: [],
71
+ preResolution: [],
72
+ afterAllResolved: [],
73
+ filterLog: [],
74
+ updateConfig: [],
75
+ };
76
+ // calculate combined checksum for all included files
77
+ if (entries.some((entry) => entry.hooks != null)) {
78
+ cookedHooks.calculatePnpmfileChecksum = async () => {
79
+ const filesToIncludeInHash = [];
80
+ for (const { includeInChecksum, file } of entries) {
81
+ if (includeInChecksum) {
82
+ filesToIncludeInHash.push(file);
83
+ }
84
+ }
85
+ filesToIncludeInHash.sort();
86
+ return createHashFromMultipleFiles(filesToIncludeInHash);
87
+ };
88
+ }
89
+ let importProvider;
90
+ const finderProviders = {};
91
+ // process hooks in order
92
+ for (const { hooks, file, finders } of entries) {
93
+ if (finders != null) {
94
+ for (const [finderName, finder] of Object.entries(finders)) {
95
+ if (mergedFinders[finderName] != null) {
96
+ const firstDefinedIn = finderProviders[finderName];
97
+ throw new PnpmError('DUPLICATE_FINDER', `Finder "${finderName}" defined in both ${firstDefinedIn} and ${file}`);
98
+ }
99
+ mergedFinders[finderName] = finder;
100
+ finderProviders[finderName] = file;
101
+ }
102
+ }
103
+ const fileHooks = hooks ?? {};
104
+ // readPackage
105
+ if (fileHooks.readPackage) {
106
+ const fn = fileHooks.readPackage;
107
+ const context = createReadPackageHookContext(file, prefix, 'readPackage');
108
+ cookedHooks.readPackage.push((pkg, _dir) => fn(pkg, context));
109
+ }
110
+ // beforePacking
111
+ if (fileHooks.beforePacking) {
112
+ const fn = fileHooks.beforePacking;
113
+ const context = createReadPackageHookContext(file, prefix, 'beforePacking');
114
+ cookedHooks.beforePacking.push((pkg, dir) => fn(pkg, dir, context));
115
+ }
116
+ // afterAllResolved
117
+ if (fileHooks.afterAllResolved) {
118
+ const fn = fileHooks.afterAllResolved;
119
+ const context = createReadPackageHookContext(file, prefix, 'afterAllResolved');
120
+ cookedHooks.afterAllResolved.push((lockfile) => fn(lockfile, context));
121
+ }
122
+ // filterLog
123
+ if (fileHooks.filterLog) {
124
+ cookedHooks.filterLog.push(fileHooks.filterLog);
125
+ }
126
+ // updateConfig
127
+ if (fileHooks.updateConfig) {
128
+ const updateConfig = fileHooks.updateConfig;
129
+ cookedHooks.updateConfig.push((config) => {
130
+ const updated = updateConfig(config);
131
+ if (updated == null) {
132
+ throw new PnpmError('CONFIG_IS_UNDEFINED', 'The updateConfig hook returned undefined');
133
+ }
134
+ return updated;
135
+ });
136
+ }
137
+ // preResolution
138
+ if (fileHooks.preResolution) {
139
+ const preRes = fileHooks.preResolution;
140
+ cookedHooks.preResolution.push((ctx) => preRes(ctx, createPreResolutionHookLogger(prefix)));
141
+ }
142
+ // importPackage: only one allowed
143
+ if (fileHooks.importPackage) {
144
+ if (importProvider) {
145
+ throw new PnpmError('MULTIPLE_IMPORT_PACKAGE', `importPackage hook defined in both ${importProvider} and ${file}`);
146
+ }
147
+ importProvider = file;
148
+ cookedHooks.importPackage = fileHooks.importPackage;
149
+ }
150
+ }
151
+ // Process top-level resolvers and fetchers exports
152
+ for (const { resolvers, fetchers } of entries) {
153
+ // Custom resolvers: merge all
154
+ if (resolvers) {
155
+ cookedHooks.customResolvers = cookedHooks.customResolvers ?? [];
156
+ cookedHooks.customResolvers.push(...resolvers);
157
+ }
158
+ // Custom fetchers: merge all
159
+ if (fetchers) {
160
+ cookedHooks.customFetchers = cookedHooks.customFetchers ?? [];
161
+ cookedHooks.customFetchers.push(...fetchers);
162
+ }
163
+ }
164
+ return {
165
+ hooks: cookedHooks,
166
+ finders: mergedFinders,
167
+ resolvedPnpmfilePaths: entries.map(({ file }) => file),
168
+ };
169
+ }
170
+ function createReadPackageHookContext(calledFrom, prefix, hook) {
171
+ return {
172
+ log: (message) => {
173
+ hookLogger.debug({ from: calledFrom, hook, message, prefix });
174
+ },
175
+ };
176
+ }
177
+ function createPreResolutionHookLogger(prefix) {
178
+ const hook = 'preResolution';
179
+ const from = 'pnpmfile';
180
+ return {
181
+ info: (message) => {
182
+ hookLogger.info({ message, prefix, hook, from }); // eslint-disable-line @typescript-eslint/no-explicit-any
183
+ },
184
+ warn: (message) => {
185
+ hookLogger.warn({ message, prefix, hook, from }); // eslint-disable-line @typescript-eslint/no-explicit-any
186
+ },
187
+ };
188
+ }
189
+ //# sourceMappingURL=requireHooks.js.map
@@ -0,0 +1,18 @@
1
+ import { PnpmError } from '@pnpm/error';
2
+ import type { CustomFetcher, CustomResolver } from '@pnpm/hooks.types';
3
+ import type { Finder } from '@pnpm/types';
4
+ import type { Hooks } from './Hooks.js';
5
+ export declare class BadReadPackageHookError extends PnpmError {
6
+ readonly pnpmfile: string;
7
+ constructor(pnpmfile: string, message: string);
8
+ }
9
+ export type Finders = Record<string, Finder>;
10
+ export interface Pnpmfile {
11
+ hooks?: Hooks;
12
+ finders?: Finders;
13
+ resolvers?: CustomResolver[];
14
+ fetchers?: CustomFetcher[];
15
+ }
16
+ export declare function requirePnpmfile(pnpmFilePath: string, prefix: string): Promise<{
17
+ pnpmfileModule: Pnpmfile | undefined;
18
+ } | undefined>;
@@ -0,0 +1,105 @@
1
+ import fs from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import path from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ import util from 'node:util';
6
+ import { PnpmError } from '@pnpm/error';
7
+ import { logger } from '@pnpm/logger';
8
+ import chalk from 'chalk';
9
+ const require = createRequire(import.meta.url);
10
+ export class BadReadPackageHookError extends PnpmError {
11
+ pnpmfile;
12
+ constructor(pnpmfile, message) {
13
+ super('BAD_READ_PACKAGE_HOOK_RESULT', `${message} Hook imported via ${pnpmfile}`);
14
+ this.pnpmfile = pnpmfile;
15
+ }
16
+ }
17
+ class PnpmFileFailError extends PnpmError {
18
+ pnpmfile;
19
+ originalError;
20
+ constructor(pnpmfile, originalError) {
21
+ super('PNPMFILE_FAIL', `Error during pnpmfile execution. pnpmfile: "${pnpmfile}". Error: "${originalError.message}".`);
22
+ this.pnpmfile = pnpmfile;
23
+ this.originalError = originalError;
24
+ }
25
+ }
26
+ export async function requirePnpmfile(pnpmFilePath, prefix) {
27
+ try {
28
+ let pnpmfile;
29
+ // Check if it's an ESM module (ends with .mjs)
30
+ if (pnpmFilePath.endsWith('.mjs')) {
31
+ const url = pathToFileURL(path.resolve(pnpmFilePath)).href;
32
+ pnpmfile = await import(url);
33
+ }
34
+ else {
35
+ // Use require for CommonJS modules
36
+ pnpmfile = require(pnpmFilePath);
37
+ }
38
+ if (typeof pnpmfile === 'undefined') {
39
+ logger.warn({
40
+ message: `Ignoring the pnpmfile at "${pnpmFilePath}". It exports "undefined".`,
41
+ prefix,
42
+ });
43
+ return { pnpmfileModule: undefined };
44
+ }
45
+ if (pnpmfile?.hooks?.readPackage && typeof pnpmfile.hooks.readPackage !== 'function') {
46
+ throw new TypeError('hooks.readPackage should be a function');
47
+ }
48
+ if (pnpmfile?.hooks?.readPackage) {
49
+ const readPackage = pnpmfile.hooks.readPackage; // eslint-disable-line
50
+ pnpmfile.hooks.readPackage = async function (pkg, ...args) {
51
+ pkg.dependencies = pkg.dependencies ?? {};
52
+ pkg.devDependencies = pkg.devDependencies ?? {};
53
+ pkg.optionalDependencies = pkg.optionalDependencies ?? {};
54
+ pkg.peerDependencies = pkg.peerDependencies ?? {};
55
+ const newPkg = await readPackage(pkg, ...args);
56
+ if (!newPkg) {
57
+ throw new BadReadPackageHookError(pnpmFilePath, 'readPackage hook did not return a package manifest object.');
58
+ }
59
+ const dependencies = ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'];
60
+ for (const dep of dependencies) {
61
+ if (newPkg[dep] != null && (typeof newPkg[dep] !== 'object' || Array.isArray(newPkg[dep]))) {
62
+ throw new BadReadPackageHookError(pnpmFilePath, `readPackage hook returned package manifest object's property '${dep}' must be an object.`);
63
+ }
64
+ }
65
+ return newPkg;
66
+ };
67
+ if (pnpmfile?.hooks?.beforePacking && typeof pnpmfile.hooks.beforePacking !== 'function') {
68
+ throw new TypeError('hooks.beforePacking should be a function');
69
+ }
70
+ }
71
+ return { pnpmfileModule: pnpmfile };
72
+ }
73
+ catch (err) {
74
+ if (err instanceof SyntaxError) {
75
+ console.error(chalk.red(`A syntax error in the "${pnpmFilePath}"\n`));
76
+ console.error(err);
77
+ process.exit(1);
78
+ }
79
+ if (!util.types.isNativeError(err)) {
80
+ throw new PnpmFileFailError(pnpmFilePath, toError(err));
81
+ }
82
+ if (!('code' in err && (err.code === 'MODULE_NOT_FOUND' || err.code === 'ERR_MODULE_NOT_FOUND')) ||
83
+ pnpmFileExistsSync(pnpmFilePath)) {
84
+ throw new PnpmFileFailError(pnpmFilePath, err);
85
+ }
86
+ return undefined;
87
+ }
88
+ }
89
+ function pnpmFileExistsSync(pnpmFilePath) {
90
+ const pnpmFileRealName = pnpmFilePath.endsWith('.cjs') || pnpmFilePath.endsWith('.mjs')
91
+ ? pnpmFilePath
92
+ : `${pnpmFilePath}.cjs`;
93
+ return fs.existsSync(pnpmFileRealName);
94
+ }
95
+ function toError(err) {
96
+ if (err instanceof Error)
97
+ return err;
98
+ try {
99
+ return new Error(String(err), { cause: err });
100
+ }
101
+ catch {
102
+ return new Error('[non-Error value thrown]', { cause: err });
103
+ }
104
+ }
105
+ //# sourceMappingURL=requirePnpmfile.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/hooks.pnpmfile",
3
- "version": "1100.0.21",
3
+ "version": "1100.0.23",
4
4
  "description": "Reading a .pnpmfile.cjs",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -27,14 +27,14 @@
27
27
  "!*.map"
28
28
  ],
29
29
  "dependencies": {
30
- "@pnpm/core-loggers": "1100.2.4",
31
- "@pnpm/crypto.hash": "1100.0.1",
32
- "@pnpm/error": "1100.0.1",
33
- "@pnpm/hooks.types": "1100.2.2",
34
- "@pnpm/lockfile.types": "1100.0.15",
35
- "@pnpm/store.controller-types": "1100.1.9",
36
- "@pnpm/types": "1101.5.0",
37
- "chalk": "^5.6.2",
30
+ "@pnpm/core-loggers": "1100.3.0",
31
+ "@pnpm/crypto.hash": "1100.0.2",
32
+ "@pnpm/error": "1100.1.0",
33
+ "@pnpm/hooks.types": "1100.2.4",
34
+ "@pnpm/lockfile.types": "1100.0.17",
35
+ "@pnpm/store.controller-types": "1100.1.11",
36
+ "@pnpm/types": "1101.7.0",
37
+ "chalk": "^6.0.0",
38
38
  "path-absolute": "^2.0.0"
39
39
  },
40
40
  "peerDependencies": {
@@ -42,10 +42,10 @@
42
42
  },
43
43
  "devDependencies": {
44
44
  "@jest/globals": "30.4.1",
45
- "@pnpm/fetching.fetcher-base": "1100.2.3",
46
- "@pnpm/hooks.pnpmfile": "1100.0.21",
45
+ "@pnpm/fetching.fetcher-base": "1100.2.5",
46
+ "@pnpm/hooks.pnpmfile": "1100.0.23",
47
47
  "@pnpm/logger": "1100.0.0",
48
- "@pnpm/test-fixtures": "1100.0.0"
48
+ "@pnpm/test-fixtures": "1100.0.1"
49
49
  },
50
50
  "engines": {
51
51
  "node": ">=22.13"