@pnpm/config.package-is-installable 1100.0.15 → 1100.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/lib/checkEngine.d.ts +13 -0
- package/lib/checkEngine.js +32 -0
- package/lib/checkPlatform.d.ts +14 -0
- package/lib/checkPlatform.js +69 -0
- package/lib/index.d.ts +46 -0
- package/lib/index.js +11 -1
- package/lib/inferPlatformFromPackageName.d.ts +13 -0
- package/lib/inferPlatformFromPackageName.js +71 -0
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @pnpm/package-is-installable
|
|
2
2
|
|
|
3
|
+
## 1100.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Fixed an installed optional dependency being left without one of its own required dependencies. When a package reached through `optionalDependencies` is installable on the current system but one of its regular `dependencies` is not, a lockfile-based install skipped that dependency and installed the parent anyway, so importing the parent failed with `MODULE_NOT_FOUND`. The dependency is now installed, and an install-check warning reports the incompatibility. A dependency is still only skipped when every path to it is optional, or when the package that pulls it in was itself skipped [#13286](https://github.com/pnpm/pnpm/issues/13286).
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies:
|
|
12
|
+
- @pnpm/cli.meta@1100.0.12
|
|
13
|
+
- @pnpm/core-loggers@1100.3.0
|
|
14
|
+
- @pnpm/engine.runtime.system-version@1100.0.7
|
|
15
|
+
- @pnpm/types@1101.7.0
|
|
16
|
+
|
|
17
|
+
## 1100.0.16
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- 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).
|
|
22
|
+
|
|
23
|
+
- Updated dependencies:
|
|
24
|
+
- @pnpm/cli.meta@1100.0.11
|
|
25
|
+
- @pnpm/core-loggers@1100.2.5
|
|
26
|
+
- @pnpm/engine.runtime.system-version@1100.0.6
|
|
27
|
+
- @pnpm/error@1100.1.0
|
|
28
|
+
- @pnpm/types@1101.6.0
|
|
29
|
+
|
|
3
30
|
## 1100.0.15
|
|
4
31
|
|
|
5
32
|
### Patch Changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PnpmError } from '@pnpm/error';
|
|
2
|
+
export declare class UnsupportedEngineError extends PnpmError {
|
|
3
|
+
wanted: WantedEngine;
|
|
4
|
+
current: Engine;
|
|
5
|
+
packageId: string;
|
|
6
|
+
constructor(packageId: string, wanted: WantedEngine, current: Engine);
|
|
7
|
+
}
|
|
8
|
+
export declare function checkEngine(packageId: string, wantedEngine: WantedEngine, currentEngine: Engine): UnsupportedEngineError | null;
|
|
9
|
+
export interface Engine {
|
|
10
|
+
node: string;
|
|
11
|
+
pnpm?: string;
|
|
12
|
+
}
|
|
13
|
+
export type WantedEngine = Partial<Engine>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { PnpmError } from '@pnpm/error';
|
|
2
|
+
import semver from 'semver';
|
|
3
|
+
export class UnsupportedEngineError extends PnpmError {
|
|
4
|
+
wanted;
|
|
5
|
+
current;
|
|
6
|
+
packageId;
|
|
7
|
+
constructor(packageId, wanted, current) {
|
|
8
|
+
super('UNSUPPORTED_ENGINE', `Unsupported engine for ${packageId}: wanted: ${JSON.stringify(wanted)} (current: ${JSON.stringify(current)})`);
|
|
9
|
+
this.packageId = packageId;
|
|
10
|
+
this.wanted = wanted;
|
|
11
|
+
this.current = current;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function checkEngine(packageId, wantedEngine, currentEngine) {
|
|
15
|
+
if (!wantedEngine)
|
|
16
|
+
return null;
|
|
17
|
+
const unsatisfiedWanted = {};
|
|
18
|
+
if (wantedEngine.node && !semver.satisfies(currentEngine.node, wantedEngine.node, { includePrerelease: true })) {
|
|
19
|
+
if (!semver.valid(currentEngine.node)) {
|
|
20
|
+
throw new PnpmError('INVALID_NODE_VERSION', `The nodeVersion setting is "${currentEngine.node}", which is not exact semver version`);
|
|
21
|
+
}
|
|
22
|
+
unsatisfiedWanted.node = wantedEngine.node;
|
|
23
|
+
}
|
|
24
|
+
if (currentEngine.pnpm && wantedEngine.pnpm && !semver.satisfies(currentEngine.pnpm, wantedEngine.pnpm, { includePrerelease: true })) {
|
|
25
|
+
unsatisfiedWanted.pnpm = wantedEngine.pnpm;
|
|
26
|
+
}
|
|
27
|
+
if (Object.keys(unsatisfiedWanted).length > 0) {
|
|
28
|
+
return new UnsupportedEngineError(packageId, unsatisfiedWanted, currentEngine);
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=checkEngine.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { PnpmError } from '@pnpm/error';
|
|
2
|
+
import type { SupportedArchitectures } from '@pnpm/types';
|
|
3
|
+
export declare class UnsupportedPlatformError extends PnpmError {
|
|
4
|
+
wanted: WantedPlatform;
|
|
5
|
+
current: Platform;
|
|
6
|
+
constructor(packageId: string, wanted: WantedPlatform, current: Platform);
|
|
7
|
+
}
|
|
8
|
+
export declare function checkPlatform(packageId: string, wantedPlatform: WantedPlatform, supportedArchitectures?: SupportedArchitectures): UnsupportedPlatformError | null;
|
|
9
|
+
export interface Platform {
|
|
10
|
+
cpu: string | string[];
|
|
11
|
+
os: string | string[];
|
|
12
|
+
libc: string | string[];
|
|
13
|
+
}
|
|
14
|
+
export type WantedPlatform = Partial<Platform>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { PnpmError } from '@pnpm/error';
|
|
2
|
+
import { familySync as getLibcFamilySync } from 'detect-libc';
|
|
3
|
+
const currentLibc = getLibcFamilySync() ?? 'unknown';
|
|
4
|
+
export class UnsupportedPlatformError extends PnpmError {
|
|
5
|
+
wanted;
|
|
6
|
+
current;
|
|
7
|
+
constructor(packageId, wanted, current) {
|
|
8
|
+
super('UNSUPPORTED_PLATFORM', `Unsupported platform for ${packageId}: wanted ${JSON.stringify(wanted)} (current: ${JSON.stringify(current)})`);
|
|
9
|
+
this.wanted = wanted;
|
|
10
|
+
this.current = current;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function checkPlatform(packageId, wantedPlatform, supportedArchitectures) {
|
|
14
|
+
const current = {
|
|
15
|
+
os: dedupeCurrent(process.platform, supportedArchitectures?.os ?? ['current']),
|
|
16
|
+
cpu: dedupeCurrent(process.arch, supportedArchitectures?.cpu ?? ['current']),
|
|
17
|
+
libc: dedupeCurrent(currentLibc, supportedArchitectures?.libc ?? ['current']),
|
|
18
|
+
};
|
|
19
|
+
const { platform, arch } = process;
|
|
20
|
+
let osOk = true;
|
|
21
|
+
let cpuOk = true;
|
|
22
|
+
let libcOk = true;
|
|
23
|
+
if (wantedPlatform.os) {
|
|
24
|
+
osOk = checkList(current.os, wantedPlatform.os);
|
|
25
|
+
}
|
|
26
|
+
if (wantedPlatform.cpu) {
|
|
27
|
+
cpuOk = checkList(current.cpu, wantedPlatform.cpu);
|
|
28
|
+
}
|
|
29
|
+
if (wantedPlatform.libc && currentLibc !== 'unknown') {
|
|
30
|
+
libcOk = checkList(current.libc, wantedPlatform.libc);
|
|
31
|
+
}
|
|
32
|
+
if (!osOk || !cpuOk || !libcOk) {
|
|
33
|
+
return new UnsupportedPlatformError(packageId, wantedPlatform, { os: platform, cpu: arch, libc: currentLibc });
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
function checkList(value, list) {
|
|
38
|
+
let tmp;
|
|
39
|
+
let match = false;
|
|
40
|
+
if (typeof list === 'string') {
|
|
41
|
+
list = [list];
|
|
42
|
+
}
|
|
43
|
+
list = list.filter((value) => typeof value === 'string');
|
|
44
|
+
if (list.length === 1 && list[0] === 'any') {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
const values = Array.isArray(value) ? value : [value];
|
|
48
|
+
for (const value of values) {
|
|
49
|
+
for (let i = 0; i < list.length; ++i) {
|
|
50
|
+
tmp = list[i];
|
|
51
|
+
if (tmp[0] === '!') {
|
|
52
|
+
tmp = tmp.slice(1);
|
|
53
|
+
if (tmp === value) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
match = match || tmp === value;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// No negation rejected any value. Accept if a positive entry matched, or if the list
|
|
63
|
+
// contains only negations (no positive constraints to satisfy).
|
|
64
|
+
return match || list.every(entry => entry[0] === '!');
|
|
65
|
+
}
|
|
66
|
+
function dedupeCurrent(current, supported) {
|
|
67
|
+
return supported.map((supported) => supported === 'current' ? current : supported);
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=checkPlatform.js.map
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { SupportedArchitectures } from '@pnpm/types';
|
|
2
|
+
import { UnsupportedEngineError, type WantedEngine } from './checkEngine.js';
|
|
3
|
+
import { UnsupportedPlatformError } from './checkPlatform.js';
|
|
4
|
+
export type { Engine } from './checkEngine.js';
|
|
5
|
+
export type { Platform, WantedPlatform } from './checkPlatform.js';
|
|
6
|
+
export { inferPlatformFromPackageName } from './inferPlatformFromPackageName.js';
|
|
7
|
+
export { UnsupportedEngineError, UnsupportedPlatformError, type WantedEngine, };
|
|
8
|
+
export interface InstallabilityManifest {
|
|
9
|
+
name: string;
|
|
10
|
+
version: string;
|
|
11
|
+
engines?: WantedEngine;
|
|
12
|
+
cpu?: string[];
|
|
13
|
+
os?: string[];
|
|
14
|
+
libc?: string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The installability verdict on its own — `null` when the package is
|
|
18
|
+
* installable — without the logging and the `engineStrict` throw that
|
|
19
|
+
* [packageIsInstallable] wraps around it. Callers that have to classify a
|
|
20
|
+
* package before they know how to report it use this, so the report is
|
|
21
|
+
* emitted exactly once.
|
|
22
|
+
*/
|
|
23
|
+
export declare function checkPackageInstallability(pkgId: string, pkg: InstallabilityManifest, options: {
|
|
24
|
+
nodeVersion?: string;
|
|
25
|
+
optional: boolean;
|
|
26
|
+
pnpmVersion?: string;
|
|
27
|
+
supportedArchitectures?: SupportedArchitectures;
|
|
28
|
+
}): null | UnsupportedEngineError | UnsupportedPlatformError;
|
|
29
|
+
export declare function packageIsInstallable(pkgId: string, pkg: InstallabilityManifest, options: {
|
|
30
|
+
engineStrict?: boolean;
|
|
31
|
+
nodeVersion?: string;
|
|
32
|
+
optional: boolean;
|
|
33
|
+
pnpmVersion?: string;
|
|
34
|
+
lockfileDir: string;
|
|
35
|
+
supportedArchitectures?: SupportedArchitectures;
|
|
36
|
+
}): boolean | null;
|
|
37
|
+
export declare function checkPackage(pkgId: string, manifest: {
|
|
38
|
+
engines?: WantedEngine;
|
|
39
|
+
cpu?: string[];
|
|
40
|
+
os?: string[];
|
|
41
|
+
libc?: string[];
|
|
42
|
+
}, options: {
|
|
43
|
+
nodeVersion?: string;
|
|
44
|
+
pnpmVersion?: string;
|
|
45
|
+
supportedArchitectures?: SupportedArchitectures;
|
|
46
|
+
}): null | UnsupportedEngineError | UnsupportedPlatformError;
|
package/lib/index.js
CHANGED
|
@@ -5,8 +5,18 @@ import { checkPlatform, UnsupportedPlatformError } from './checkPlatform.js';
|
|
|
5
5
|
import { inferPlatformFromPackageName } from './inferPlatformFromPackageName.js';
|
|
6
6
|
export { inferPlatformFromPackageName } from './inferPlatformFromPackageName.js';
|
|
7
7
|
export { UnsupportedEngineError, UnsupportedPlatformError, };
|
|
8
|
+
/**
|
|
9
|
+
* The installability verdict on its own — `null` when the package is
|
|
10
|
+
* installable — without the logging and the `engineStrict` throw that
|
|
11
|
+
* [packageIsInstallable] wraps around it. Callers that have to classify a
|
|
12
|
+
* package before they know how to report it use this, so the report is
|
|
13
|
+
* emitted exactly once.
|
|
14
|
+
*/
|
|
15
|
+
export function checkPackageInstallability(pkgId, pkg, options) {
|
|
16
|
+
return checkPackage(pkgId, { engines: pkg.engines, ...effectivePlatform(pkg, options.optional) }, options);
|
|
17
|
+
}
|
|
8
18
|
export function packageIsInstallable(pkgId, pkg, options) {
|
|
9
|
-
const warn =
|
|
19
|
+
const warn = checkPackageInstallability(pkgId, pkg, options);
|
|
10
20
|
if (warn == null)
|
|
11
21
|
return true;
|
|
12
22
|
installCheckLogger.warn({
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface PlatformInferredFromPackageName {
|
|
2
|
+
os?: string[];
|
|
3
|
+
cpu?: string[];
|
|
4
|
+
libc?: string[];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Infers the supported platforms of a package from the tokens of its name,
|
|
8
|
+
* e.g. `@nx/nx-win32-arm64-msvc` → `{ os: ['win32'], cpu: ['arm64'] }`.
|
|
9
|
+
* Platform-specific binary packages follow this naming convention, which is
|
|
10
|
+
* the only platform signal left when their os/cpu/libc manifest fields are
|
|
11
|
+
* absent. Returns null when no platform token is recognized in the name.
|
|
12
|
+
*/
|
|
13
|
+
export declare function inferPlatformFromPackageName(name: string): PlatformInferredFromPackageName | null;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const OS_BY_TOKEN = new Map([
|
|
2
|
+
['aix', 'aix'],
|
|
3
|
+
['android', 'android'],
|
|
4
|
+
['darwin', 'darwin'],
|
|
5
|
+
['macos', 'darwin'],
|
|
6
|
+
['osx', 'darwin'],
|
|
7
|
+
['freebsd', 'freebsd'],
|
|
8
|
+
['linux', 'linux'],
|
|
9
|
+
['netbsd', 'netbsd'],
|
|
10
|
+
['openbsd', 'openbsd'],
|
|
11
|
+
['openharmony', 'openharmony'],
|
|
12
|
+
['sunos', 'sunos'],
|
|
13
|
+
['win32', 'win32'],
|
|
14
|
+
['windows', 'win32'],
|
|
15
|
+
]);
|
|
16
|
+
const CPU_BY_TOKEN = new Map([
|
|
17
|
+
['arm', 'arm'],
|
|
18
|
+
['armv6', 'arm'],
|
|
19
|
+
['armv7', 'arm'],
|
|
20
|
+
['arm64', 'arm64'],
|
|
21
|
+
['aarch64', 'arm64'],
|
|
22
|
+
['ia32', 'ia32'],
|
|
23
|
+
['loong64', 'loong64'],
|
|
24
|
+
['mips64el', 'mips64el'],
|
|
25
|
+
['ppc64', 'ppc64'],
|
|
26
|
+
['ppc64le', 'ppc64'],
|
|
27
|
+
['riscv64', 'riscv64'],
|
|
28
|
+
['s390x', 's390x'],
|
|
29
|
+
['x64', 'x64'],
|
|
30
|
+
['amd64', 'x64'],
|
|
31
|
+
['wasm32', 'wasm32'],
|
|
32
|
+
]);
|
|
33
|
+
const LIBC_BY_TOKEN = new Map([
|
|
34
|
+
['glibc', 'glibc'],
|
|
35
|
+
['gnu', 'glibc'],
|
|
36
|
+
['gnueabihf', 'glibc'],
|
|
37
|
+
['musl', 'musl'],
|
|
38
|
+
['musleabihf', 'musl'],
|
|
39
|
+
]);
|
|
40
|
+
/**
|
|
41
|
+
* Infers the supported platforms of a package from the tokens of its name,
|
|
42
|
+
* e.g. `@nx/nx-win32-arm64-msvc` → `{ os: ['win32'], cpu: ['arm64'] }`.
|
|
43
|
+
* Platform-specific binary packages follow this naming convention, which is
|
|
44
|
+
* the only platform signal left when their os/cpu/libc manifest fields are
|
|
45
|
+
* absent. Returns null when no platform token is recognized in the name.
|
|
46
|
+
*/
|
|
47
|
+
export function inferPlatformFromPackageName(name) {
|
|
48
|
+
const nameWithoutScope = name.includes('/') ? name.slice(name.indexOf('/') + 1) : name;
|
|
49
|
+
const tokens = nameWithoutScope.toLowerCase().split(/[-_.]/);
|
|
50
|
+
const os = pickTokenValues(tokens, OS_BY_TOKEN);
|
|
51
|
+
const cpu = pickTokenValues(tokens, CPU_BY_TOKEN);
|
|
52
|
+
const libc = pickTokenValues(tokens, LIBC_BY_TOKEN);
|
|
53
|
+
if (os == null && cpu == null && libc == null)
|
|
54
|
+
return null;
|
|
55
|
+
return {
|
|
56
|
+
...(os != null ? { os } : {}),
|
|
57
|
+
...(cpu != null ? { cpu } : {}),
|
|
58
|
+
...(libc != null ? { libc } : {}),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function pickTokenValues(tokens, valueByToken) {
|
|
62
|
+
const values = new Set();
|
|
63
|
+
for (const token of tokens) {
|
|
64
|
+
const value = valueByToken.get(token);
|
|
65
|
+
if (value != null) {
|
|
66
|
+
values.add(value);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return values.size > 0 ? Array.from(values) : undefined;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=inferPlatformFromPackageName.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/config.package-is-installable",
|
|
3
|
-
"version": "1100.0
|
|
3
|
+
"version": "1100.1.0",
|
|
4
4
|
"description": "Checks if a package is installable on the current system",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -27,22 +27,22 @@
|
|
|
27
27
|
"!*.map"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@pnpm/cli.meta": "1100.0.
|
|
31
|
-
"@pnpm/core-loggers": "1100.
|
|
32
|
-
"@pnpm/engine.runtime.system-version": "1100.0.
|
|
33
|
-
"@pnpm/error": "1100.0
|
|
34
|
-
"@pnpm/types": "1101.
|
|
30
|
+
"@pnpm/cli.meta": "1100.0.12",
|
|
31
|
+
"@pnpm/core-loggers": "1100.3.0",
|
|
32
|
+
"@pnpm/engine.runtime.system-version": "1100.0.7",
|
|
33
|
+
"@pnpm/error": "1100.1.0",
|
|
34
|
+
"@pnpm/types": "1101.7.0",
|
|
35
35
|
"detect-libc": "^2.1.2",
|
|
36
36
|
"execa": "npm:safe-execa@0.3.0",
|
|
37
37
|
"memoize": "^11.0.0",
|
|
38
|
-
"semver": "^7.8.
|
|
38
|
+
"semver": "^7.8.5"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"@pnpm/logger": "^1100.0.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@jest/globals": "30.4.1",
|
|
45
|
-
"@pnpm/config.package-is-installable": "1100.0
|
|
45
|
+
"@pnpm/config.package-is-installable": "1100.1.0",
|
|
46
46
|
"@pnpm/logger": "1100.0.0",
|
|
47
47
|
"@types/semver": "7.7.1"
|
|
48
48
|
},
|