@pnpm/resolving.npm-resolver 1101.0.2 → 1101.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/lib/index.d.ts +16 -3
- package/lib/index.js +123 -42
- package/lib/parseBareSpecifier.d.ts +5 -0
- package/lib/parseBareSpecifier.js +90 -8
- package/package.json +22 -22
package/lib/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { PackageMeta } from '@pnpm/resolving.registry.types';
|
|
|
4
4
|
import type { DirectoryResolution, PkgResolutionId, PreferredVersions, ResolveResult, TarballResolution, WantedDependency, WorkspacePackages } from '@pnpm/resolving.resolver-base';
|
|
5
5
|
import type { DependencyManifest, PackageVersionPolicy, PinnedVersion, Registries, TrustPolicy } from '@pnpm/types';
|
|
6
6
|
import { fetchMetadataFromFromRegistry, type FetchMetadataFromFromRegistryOptions, RegistryResponseError } from './fetch.js';
|
|
7
|
-
import { parseBareSpecifier, type RegistryPackageSpec } from './parseBareSpecifier.js';
|
|
7
|
+
import { BUILTIN_NAMED_REGISTRIES, parseBareSpecifier, type RegistryPackageSpec } from './parseBareSpecifier.js';
|
|
8
8
|
import { type PackageMetaCache, pickPackage, type PickPackageOptions } from './pickPackage.js';
|
|
9
9
|
import { pickPackageFromMeta, pickVersionByVersionRange } from './pickPackageFromMeta.js';
|
|
10
10
|
import { workspacePrefToNpm } from './workspacePrefToNpm.js';
|
|
@@ -20,7 +20,8 @@ export declare class NoMatchingVersionError extends PnpmError {
|
|
|
20
20
|
readonly immatureVersion?: string;
|
|
21
21
|
constructor(opts: NoMatchingVersionErrorOptions);
|
|
22
22
|
}
|
|
23
|
-
export
|
|
23
|
+
export declare function formatTimeAgo(date: Date): string | null;
|
|
24
|
+
export { BUILTIN_NAMED_REGISTRIES, fetchMetadataFromFromRegistry, type FetchMetadataFromFromRegistryOptions, type PackageMeta, type PackageMetaCache, parseBareSpecifier, pickPackageFromMeta, pickVersionByVersionRange, type RegistryPackageSpec, RegistryResponseError, workspacePrefToNpm, };
|
|
24
25
|
export { whichVersionIsPinned } from './whichVersionIsPinned.js';
|
|
25
26
|
export interface ResolverFactoryOptions {
|
|
26
27
|
cacheDir: string;
|
|
@@ -32,6 +33,7 @@ export interface ResolverFactoryOptions {
|
|
|
32
33
|
retry?: RetryTimeoutOptions;
|
|
33
34
|
timeout?: number;
|
|
34
35
|
registries: Registries;
|
|
36
|
+
namedRegistries?: Record<string, string>;
|
|
35
37
|
saveWorkspaceProtocol?: boolean | 'rolling';
|
|
36
38
|
preserveAbsolutePaths?: boolean;
|
|
37
39
|
strictPublishedByCheck?: boolean;
|
|
@@ -54,6 +56,14 @@ export interface JsrResolveResult extends ResolveResult {
|
|
|
54
56
|
resolution: TarballResolution;
|
|
55
57
|
resolvedVia: 'jsr-registry';
|
|
56
58
|
}
|
|
59
|
+
export interface NamedRegistryResolveResult extends ResolveResult {
|
|
60
|
+
alias: string;
|
|
61
|
+
/** The named-registry alias that was matched, e.g. `gh` or a user-defined name. */
|
|
62
|
+
registryName: string;
|
|
63
|
+
manifest: DependencyManifest;
|
|
64
|
+
resolution: TarballResolution;
|
|
65
|
+
resolvedVia: 'named-registry';
|
|
66
|
+
}
|
|
57
67
|
export interface WorkspaceResolveResult extends ResolveResult {
|
|
58
68
|
manifest: DependencyManifest;
|
|
59
69
|
resolution: DirectoryResolution;
|
|
@@ -61,16 +71,19 @@ export interface WorkspaceResolveResult extends ResolveResult {
|
|
|
61
71
|
}
|
|
62
72
|
export type NpmResolver = (wantedDependency: WantedDependency & {
|
|
63
73
|
optional?: boolean;
|
|
64
|
-
}, opts: ResolveFromNpmOptions) => Promise<NpmResolveResult | JsrResolveResult | WorkspaceResolveResult | null>;
|
|
74
|
+
}, opts: ResolveFromNpmOptions) => Promise<NpmResolveResult | JsrResolveResult | NamedRegistryResolveResult | WorkspaceResolveResult | null>;
|
|
65
75
|
export declare function createNpmResolver(fetchFromRegistry: FetchFromRegistry, getAuthHeader: GetAuthHeader, opts: ResolverFactoryOptions): {
|
|
66
76
|
resolveFromNpm: NpmResolver;
|
|
67
77
|
resolveFromJsr: NpmResolver;
|
|
78
|
+
resolveFromNamedRegistry: NpmResolver;
|
|
68
79
|
clearCache: () => void;
|
|
69
80
|
};
|
|
70
81
|
export interface ResolveFromNpmContext {
|
|
71
82
|
pickPackage: (spec: RegistryPackageSpec, opts: PickPackageOptions) => ReturnType<typeof pickPackage>;
|
|
72
83
|
getAuthHeaderValueByURI: (registry: string) => string | undefined;
|
|
73
84
|
registries: Registries;
|
|
85
|
+
namedRegistries: Record<string, string>;
|
|
86
|
+
namedRegistryNames: ReadonlySet<string>;
|
|
74
87
|
saveWorkspaceProtocol?: boolean | 'rolling';
|
|
75
88
|
peekManifestFromStore?: (opts: {
|
|
76
89
|
id: PkgResolutionId;
|
package/lib/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import ssri from 'ssri';
|
|
|
13
13
|
import versionSelectorType from 'version-selector-type';
|
|
14
14
|
import { fetchMetadataFromFromRegistry, RegistryResponseError } from './fetch.js';
|
|
15
15
|
import { normalizeRegistryUrl } from './normalizeRegistryUrl.js';
|
|
16
|
-
import { parseBareSpecifier, parseJsrSpecifierToRegistryPackageSpec, } from './parseBareSpecifier.js';
|
|
16
|
+
import { BUILTIN_NAMED_REGISTRIES, parseBareSpecifier, parseJsrSpecifierToRegistryPackageSpec, parseNamedRegistrySpecifierToRegistryPackageSpec, } from './parseBareSpecifier.js';
|
|
17
17
|
import { pickPackage, } from './pickPackage.js';
|
|
18
18
|
import { pickPackageFromMeta, pickVersionByVersionRange } from './pickPackageFromMeta.js';
|
|
19
19
|
import { failIfTrustDowngraded } from './trustChecks.js';
|
|
@@ -29,7 +29,7 @@ export class NoMatchingVersionError extends PnpmError {
|
|
|
29
29
|
let errorMessage;
|
|
30
30
|
if (opts.publishedBy && opts.immatureVersion && opts.packageMeta.time) {
|
|
31
31
|
const time = new Date(opts.packageMeta.time[opts.immatureVersion]);
|
|
32
|
-
const releaseAgeText = formatTimeAgo(time);
|
|
32
|
+
const releaseAgeText = formatTimeAgo(time) ?? 'just now';
|
|
33
33
|
const pkgName = opts.wantedDependency.alias ?? opts.packageMeta.name;
|
|
34
34
|
errorMessage = `Version ${opts.immatureVersion} (released ${releaseAgeText}) of ${pkgName} does not meet the minimumReleaseAge constraint`;
|
|
35
35
|
}
|
|
@@ -41,25 +41,36 @@ export class NoMatchingVersionError extends PnpmError {
|
|
|
41
41
|
this.immatureVersion = opts.immatureVersion;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
function formatTimeAgo(date) {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (diffMs < 60 * 1000) {
|
|
49
|
-
return 'just now';
|
|
50
|
-
}
|
|
51
|
-
const diffMinutes = Math.floor(diffMs / (60 * 1000));
|
|
52
|
-
const diffHours = Math.floor(diffMs / (60 * 60 * 1000));
|
|
53
|
-
const diffDays = Math.floor(diffMs / (24 * 60 * 60 * 1000));
|
|
54
|
-
if (diffHours >= 48) {
|
|
55
|
-
return `${diffDays} day${diffDays === 1 ? '' : 's'} ago`;
|
|
44
|
+
export function formatTimeAgo(date) {
|
|
45
|
+
const ts = date.getTime();
|
|
46
|
+
if (isNaN(ts)) {
|
|
47
|
+
return null;
|
|
56
48
|
}
|
|
57
|
-
|
|
58
|
-
|
|
49
|
+
const now = Date.now();
|
|
50
|
+
const diffMs = now - ts;
|
|
51
|
+
// Handle clock skew (future dates)
|
|
52
|
+
if (diffMs < 0) {
|
|
53
|
+
return null;
|
|
59
54
|
}
|
|
60
|
-
|
|
55
|
+
const diffSec = Math.floor(diffMs / 1000);
|
|
56
|
+
const diffMin = Math.floor(diffSec / 60);
|
|
57
|
+
const diffHour = Math.floor(diffMin / 60);
|
|
58
|
+
const diffDay = Math.floor(diffHour / 24);
|
|
59
|
+
const diffMonth = Math.floor(diffDay / 30);
|
|
60
|
+
const diffYear = Math.floor(diffDay / 365);
|
|
61
|
+
if (diffYear > 0)
|
|
62
|
+
return `${diffYear} year${diffYear === 1 ? '' : 's'} ago`;
|
|
63
|
+
if (diffMonth > 0)
|
|
64
|
+
return `${diffMonth} month${diffMonth === 1 ? '' : 's'} ago`;
|
|
65
|
+
if (diffDay > 0)
|
|
66
|
+
return `${diffDay} day${diffDay === 1 ? '' : 's'} ago`;
|
|
67
|
+
if (diffHour > 0)
|
|
68
|
+
return `${diffHour} hour${diffHour === 1 ? '' : 's'} ago`;
|
|
69
|
+
if (diffMin > 0)
|
|
70
|
+
return `${diffMin} minute${diffMin === 1 ? '' : 's'} ago`;
|
|
71
|
+
return 'a few seconds ago';
|
|
61
72
|
}
|
|
62
|
-
export { fetchMetadataFromFromRegistry, parseBareSpecifier, pickPackageFromMeta, pickVersionByVersionRange, RegistryResponseError, workspacePrefToNpm, };
|
|
73
|
+
export { BUILTIN_NAMED_REGISTRIES, fetchMetadataFromFromRegistry, parseBareSpecifier, pickPackageFromMeta, pickVersionByVersionRange, RegistryResponseError, workspacePrefToNpm, };
|
|
63
74
|
export { whichVersionIsPinned } from './whichVersionIsPinned.js';
|
|
64
75
|
export function createNpmResolver(fetchFromRegistry, getAuthHeader, opts) {
|
|
65
76
|
if (typeof opts.cacheDir !== 'string') {
|
|
@@ -103,6 +114,8 @@ export function createNpmResolver(fetchFromRegistry, getAuthHeader, opts) {
|
|
|
103
114
|
return request;
|
|
104
115
|
};
|
|
105
116
|
}
|
|
117
|
+
const namedRegistries = mergeNamedRegistries(opts.namedRegistries);
|
|
118
|
+
const namedRegistryNames = new Set(Object.keys(namedRegistries));
|
|
106
119
|
const ctx = {
|
|
107
120
|
getAuthHeaderValueByURI: getAuthHeader,
|
|
108
121
|
pickPackage: pickPackage.bind(null, {
|
|
@@ -117,12 +130,15 @@ export function createNpmResolver(fetchFromRegistry, getAuthHeader, opts) {
|
|
|
117
130
|
ignoreMissingTimeField: opts.ignoreMissingTimeField,
|
|
118
131
|
}),
|
|
119
132
|
registries: opts.registries,
|
|
133
|
+
namedRegistries,
|
|
134
|
+
namedRegistryNames,
|
|
120
135
|
saveWorkspaceProtocol: opts.saveWorkspaceProtocol,
|
|
121
136
|
peekManifestFromStore,
|
|
122
137
|
};
|
|
123
138
|
return {
|
|
124
139
|
resolveFromNpm: resolveNpm.bind(null, ctx),
|
|
125
140
|
resolveFromJsr: resolveJsr.bind(null, ctx),
|
|
141
|
+
resolveFromNamedRegistry: resolveFromNamedRegistry.bind(null, ctx),
|
|
126
142
|
clearCache: () => {
|
|
127
143
|
if ('clear' in metaCache && typeof metaCache.clear === 'function') {
|
|
128
144
|
metaCache.clear();
|
|
@@ -326,52 +342,117 @@ async function resolveNpm(ctx, wantedDependency, opts) {
|
|
|
326
342
|
async function resolveJsr(ctx, wantedDependency, opts) {
|
|
327
343
|
if (!wantedDependency.bareSpecifier)
|
|
328
344
|
return null;
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
345
|
+
const spec = parseJsrSpecifierToRegistryPackageSpec(wantedDependency.bareSpecifier, wantedDependency.alias, opts.defaultTag ?? 'latest');
|
|
346
|
+
if (spec == null)
|
|
347
|
+
return null;
|
|
348
|
+
const picked = await pickFromSimpleRegistry(ctx, wantedDependency, opts, spec, ctx.registries['@jsr']); // '@jsr' is always defined
|
|
349
|
+
return {
|
|
350
|
+
...picked,
|
|
351
|
+
normalizedBareSpecifier: opts.calcSpecifier
|
|
352
|
+
? calcPrefixedSpecifier('jsr:', spec.jsrPkgName, wantedDependency, picked.manifest.version, opts.pinnedVersion)
|
|
353
|
+
: undefined,
|
|
354
|
+
resolvedVia: 'jsr-registry',
|
|
355
|
+
alias: spec.jsrPkgName,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
// Merges user-supplied named-registry aliases (from config) on top of pnpm's
|
|
359
|
+
// built-in defaults (e.g. `gh` → GitHub Packages). User entries take precedence
|
|
360
|
+
// so GHES users can point `gh` at their enterprise host. URLs are validated
|
|
361
|
+
// here so typos like `npm.work.example.com` (no scheme) surface at startup
|
|
362
|
+
// rather than as a confusing 404 during resolution. The named-registry
|
|
363
|
+
// resolver runs last in the resolution chain, so an alias that collides with
|
|
364
|
+
// another specifier scheme (e.g. `git`, `github`, `jsr`) is silently shadowed
|
|
365
|
+
// by that scheme's dedicated resolver — no cross-resolver knowledge needed.
|
|
366
|
+
function mergeNamedRegistries(userDefined) {
|
|
367
|
+
const merged = { ...BUILTIN_NAMED_REGISTRIES };
|
|
368
|
+
if (!userDefined)
|
|
369
|
+
return merged;
|
|
370
|
+
for (const [alias, url] of Object.entries(userDefined)) {
|
|
371
|
+
if (typeof url !== 'string' || !isValidHttpUrl(url)) {
|
|
372
|
+
throw new PnpmError('INVALID_NAMED_REGISTRY_URL', `The named registry alias '${alias}' is mapped to '${String(url)}', which is not a valid http(s) URL.`, { hint: 'Provide a URL that starts with http:// or https://, e.g. https://npm.pkg.example.com/' });
|
|
373
|
+
}
|
|
374
|
+
merged[alias] = url;
|
|
375
|
+
}
|
|
376
|
+
return merged;
|
|
377
|
+
}
|
|
378
|
+
function isValidHttpUrl(url) {
|
|
379
|
+
try {
|
|
380
|
+
const parsed = new URL(url);
|
|
381
|
+
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
// Resolves a `<alias>:` specifier from one of the configured named registries.
|
|
388
|
+
// The `gh:` alias ships as a built-in default pointing at the GitHub Packages
|
|
389
|
+
// npm registry; additional aliases come from pnpm-workspace.yaml's
|
|
390
|
+
// `namedRegistries` field. Auth tokens are looked up by the resolved registry
|
|
391
|
+
// URL, so a `//npm.pkg.github.com/:_authToken=...` entry in `.npmrc` is
|
|
392
|
+
// picked up automatically for `gh:` specifiers (and analogously for any user-
|
|
393
|
+
// configured alias).
|
|
394
|
+
async function resolveFromNamedRegistry(ctx, wantedDependency, opts) {
|
|
395
|
+
if (!wantedDependency.bareSpecifier)
|
|
396
|
+
return null;
|
|
397
|
+
const spec = parseNamedRegistrySpecifierToRegistryPackageSpec(wantedDependency.bareSpecifier, ctx.namedRegistryNames, wantedDependency.alias, opts.defaultTag ?? 'latest');
|
|
332
398
|
if (spec == null)
|
|
333
399
|
return null;
|
|
400
|
+
const registry = ctx.namedRegistries[spec.registryName];
|
|
401
|
+
if (!registry)
|
|
402
|
+
return null; // defensive: should never trigger because parse checks the alias set
|
|
403
|
+
const picked = await pickFromSimpleRegistry(ctx, wantedDependency, opts, spec, registry);
|
|
404
|
+
return {
|
|
405
|
+
...picked,
|
|
406
|
+
normalizedBareSpecifier: opts.calcSpecifier
|
|
407
|
+
? calcPrefixedSpecifier(`${spec.registryName}:`, spec.name, wantedDependency, picked.manifest.version, opts.pinnedVersion)
|
|
408
|
+
: undefined,
|
|
409
|
+
resolvedVia: 'named-registry',
|
|
410
|
+
registryName: spec.registryName,
|
|
411
|
+
// Exposes the scoped package name so callers that omit an explicit alias
|
|
412
|
+
// (e.g. `pnpm add gh:@acme/foo`) record the dependency under `@acme/foo`.
|
|
413
|
+
alias: spec.name,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
// Shared inner shell for resolvers that pull from a single registry URL with
|
|
417
|
+
// an already-parsed RegistryPackageSpec (jsr, named-registry). Returns the
|
|
418
|
+
// fields common to their result envelopes; each caller adds its own
|
|
419
|
+
// resolvedVia, alias, and normalizedBareSpecifier.
|
|
420
|
+
async function pickFromSimpleRegistry(ctx, wantedDependency, opts, spec, registry) {
|
|
334
421
|
const authHeaderValue = ctx.getAuthHeaderValueByURI(registry);
|
|
335
422
|
const { meta, pickedPackage } = await ctx.pickPackage(spec, {
|
|
336
423
|
pickLowestVersion: opts.pickLowestVersion,
|
|
337
424
|
publishedBy: opts.publishedBy,
|
|
425
|
+
publishedByExclude: opts.publishedByExclude,
|
|
338
426
|
authHeaderValue,
|
|
339
427
|
dryRun: opts.dryRun === true,
|
|
340
428
|
preferredVersionSelectors: opts.preferredVersions?.[spec.name],
|
|
341
429
|
registry,
|
|
342
430
|
includeLatestTag: opts.update === 'latest',
|
|
431
|
+
optional: wantedDependency.optional,
|
|
343
432
|
});
|
|
344
433
|
if (pickedPackage == null) {
|
|
345
434
|
throw new NoMatchingVersionError({ wantedDependency, packageMeta: meta, registry });
|
|
346
435
|
}
|
|
347
|
-
const id = `${pickedPackage.name}@${pickedPackage.version}`;
|
|
348
|
-
const resolution = {
|
|
349
|
-
integrity: getIntegrity(pickedPackage.dist),
|
|
350
|
-
tarball: normalizeRegistryUrl(pickedPackage.dist.tarball),
|
|
351
|
-
};
|
|
352
436
|
return {
|
|
353
|
-
id
|
|
437
|
+
id: `${pickedPackage.name}@${pickedPackage.version}`,
|
|
354
438
|
latest: meta['dist-tags'].latest,
|
|
355
439
|
manifest: pickedPackage,
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
version: pickedPackage.version,
|
|
361
|
-
defaultPinnedVersion: opts.pinnedVersion,
|
|
362
|
-
})
|
|
363
|
-
: undefined,
|
|
364
|
-
resolution,
|
|
365
|
-
resolvedVia: 'jsr-registry',
|
|
440
|
+
resolution: {
|
|
441
|
+
integrity: getIntegrity(pickedPackage.dist),
|
|
442
|
+
tarball: normalizeRegistryUrl(pickedPackage.dist.tarball),
|
|
443
|
+
},
|
|
366
444
|
publishedAt: meta.time?.[pickedPackage.version],
|
|
367
|
-
alias: spec.jsrPkgName,
|
|
368
445
|
};
|
|
369
446
|
}
|
|
370
|
-
|
|
447
|
+
// Builds a `<prefix><pkgName>@<range>` specifier (or a bare `<prefix><range>`
|
|
448
|
+
// when the dependency alias matches the package name). Shared between the
|
|
449
|
+
// jsr and named-registry resolvers since they only differ in `prefix` and
|
|
450
|
+
// which spec field holds the package name.
|
|
451
|
+
function calcPrefixedSpecifier(prefix, pkgName, wantedDependency, version, defaultPinnedVersion) {
|
|
371
452
|
const range = calcRange(version, wantedDependency, defaultPinnedVersion);
|
|
372
|
-
if (!wantedDependency.alias ||
|
|
373
|
-
return
|
|
374
|
-
return
|
|
453
|
+
if (!wantedDependency.alias || pkgName === wantedDependency.alias)
|
|
454
|
+
return `${prefix}${range}`;
|
|
455
|
+
return `${prefix}${pkgName}@${range}`;
|
|
375
456
|
}
|
|
376
457
|
function calcSpecifier({ wantedDependency, spec, version, defaultPinnedVersion, }) {
|
|
377
458
|
if (wantedDependency.prevSpecifier === wantedDependency.bareSpecifier && wantedDependency.prevSpecifier && versionSelectorType(wantedDependency.prevSpecifier)?.type === 'tag') {
|
|
@@ -9,3 +9,8 @@ export interface JsrRegistryPackageSpec extends RegistryPackageSpec {
|
|
|
9
9
|
jsrPkgName: string;
|
|
10
10
|
}
|
|
11
11
|
export declare function parseJsrSpecifierToRegistryPackageSpec(rawSpecifier: string, alias: string | undefined, defaultTag: string): JsrRegistryPackageSpec | null;
|
|
12
|
+
export declare const BUILTIN_NAMED_REGISTRIES: Readonly<Record<string, string>>;
|
|
13
|
+
export interface NamedRegistryPackageSpec extends RegistryPackageSpec {
|
|
14
|
+
registryName: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function parseNamedRegistrySpecifierToRegistryPackageSpec(rawSpecifier: string, knownRegistryNames: ReadonlySet<string>, packageAlias: string | undefined, defaultTag: string): NamedRegistryPackageSpec | null;
|
|
@@ -1,18 +1,29 @@
|
|
|
1
|
+
import { PnpmError } from '@pnpm/error';
|
|
1
2
|
import { parseJsrSpecifier } from '@pnpm/resolving.jsr-specifier-parser';
|
|
2
|
-
import parseNpmTarballUrl from 'parse-npm-tarball-url';
|
|
3
|
+
import { parseNpmTarballUrl } from 'parse-npm-tarball-url';
|
|
4
|
+
import semver from 'semver';
|
|
3
5
|
import getVersionSelectorType from 'version-selector-type';
|
|
4
6
|
export function parseBareSpecifier(bareSpecifier, alias, defaultTag, registry) {
|
|
5
7
|
let name = alias;
|
|
6
8
|
if (bareSpecifier.startsWith('npm:')) {
|
|
7
9
|
bareSpecifier = bareSpecifier.slice(4);
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
// `npm:<version_selector>` — fall back to the outer dependency alias as
|
|
11
|
+
// the package name, mirroring the named-registry shape (e.g. `gh:^1.0.0`).
|
|
12
|
+
// Restricted to semver ranges/versions so unscoped package names like
|
|
13
|
+
// `npm:is-positive` keep their npm package-aliasing meaning.
|
|
14
|
+
if (alias && semver.validRange(bareSpecifier) != null) {
|
|
15
|
+
name = alias;
|
|
12
16
|
}
|
|
13
17
|
else {
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
const index = bareSpecifier.lastIndexOf('@');
|
|
19
|
+
if (index < 1) {
|
|
20
|
+
name = bareSpecifier;
|
|
21
|
+
bareSpecifier = defaultTag;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
name = bareSpecifier.slice(0, index);
|
|
25
|
+
bareSpecifier = bareSpecifier.slice(index + 1);
|
|
26
|
+
}
|
|
16
27
|
}
|
|
17
28
|
}
|
|
18
29
|
if (name) {
|
|
@@ -26,7 +37,7 @@ export function parseBareSpecifier(bareSpecifier, alias, defaultTag, registry) {
|
|
|
26
37
|
}
|
|
27
38
|
}
|
|
28
39
|
if (bareSpecifier.startsWith(registry)) {
|
|
29
|
-
const pkg = parseNpmTarballUrl
|
|
40
|
+
const pkg = parseNpmTarballUrl(bareSpecifier);
|
|
30
41
|
if (pkg != null) {
|
|
31
42
|
return {
|
|
32
43
|
fetchSpec: pkg.version,
|
|
@@ -52,4 +63,75 @@ export function parseJsrSpecifierToRegistryPackageSpec(rawSpecifier, alias, defa
|
|
|
52
63
|
jsrPkgName: spec.jsrPkgName,
|
|
53
64
|
};
|
|
54
65
|
}
|
|
66
|
+
export const BUILTIN_NAMED_REGISTRIES = Object.freeze({
|
|
67
|
+
gh: 'https://npm.pkg.github.com/',
|
|
68
|
+
});
|
|
69
|
+
// Parses a named-registry specifier of the shape `<alias>:<body>` into a
|
|
70
|
+
// RegistryPackageSpec. Returns `null` when the specifier does not use one of
|
|
71
|
+
// the configured aliases, so the caller can fall through to other resolvers.
|
|
72
|
+
// Supported shapes:
|
|
73
|
+
// - `<alias>:[@<owner>/]<name>[@<version_selector>]`
|
|
74
|
+
// - `<alias>:<version_selector>` paired with a package alias
|
|
75
|
+
export function parseNamedRegistrySpecifierToRegistryPackageSpec(rawSpecifier, knownRegistryNames, packageAlias, defaultTag) {
|
|
76
|
+
const colon = rawSpecifier.indexOf(':');
|
|
77
|
+
if (colon <= 0)
|
|
78
|
+
return null;
|
|
79
|
+
const registryName = rawSpecifier.substring(0, colon);
|
|
80
|
+
if (!knownRegistryNames.has(registryName))
|
|
81
|
+
return null;
|
|
82
|
+
const body = rawSpecifier.substring(colon + 1);
|
|
83
|
+
let pkgName;
|
|
84
|
+
let versionSelector;
|
|
85
|
+
if (semver.validRange(body) != null) {
|
|
86
|
+
// `<alias>:<version_selector>` — fall back to the dependency alias as
|
|
87
|
+
// the package name. Unresolvable without one.
|
|
88
|
+
if (!packageAlias)
|
|
89
|
+
return null;
|
|
90
|
+
pkgName = packageAlias;
|
|
91
|
+
versionSelector = body;
|
|
92
|
+
}
|
|
93
|
+
else if (body[0] === '@') {
|
|
94
|
+
// `<alias>:@<owner>/<name>[@<version_selector>]` — scoped package.
|
|
95
|
+
const index = body.lastIndexOf('@');
|
|
96
|
+
if (index === 0) {
|
|
97
|
+
pkgName = body;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
pkgName = body.substring(0, index);
|
|
101
|
+
versionSelector = body.substring(index + '@'.length);
|
|
102
|
+
}
|
|
103
|
+
if (pkgName.indexOf('/') === -1 || pkgName.endsWith('/')) {
|
|
104
|
+
throw new PnpmError('INVALID_NAMED_REGISTRY_PACKAGE_NAME', `The package name '${pkgName}' in named registry '${registryName}:' is invalid`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else if (packageAlias?.startsWith('@')) {
|
|
108
|
+
// `<alias>:<tag>` paired with a scoped alias — body is a version
|
|
109
|
+
// selector (tag/dist-tag). Mirrors GitHub Packages, where the package
|
|
110
|
+
// is always scoped and a bare body is a tag.
|
|
111
|
+
pkgName = packageAlias;
|
|
112
|
+
versionSelector = body;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// `<alias>:<name>[@<version_selector>]` — unscoped package in body.
|
|
116
|
+
const index = body.lastIndexOf('@');
|
|
117
|
+
if (index < 1) {
|
|
118
|
+
pkgName = body;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
pkgName = body.substring(0, index);
|
|
122
|
+
versionSelector = body.substring(index + '@'.length);
|
|
123
|
+
}
|
|
124
|
+
if (!pkgName)
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
const selector = getVersionSelectorType(versionSelector ?? defaultTag);
|
|
128
|
+
if (selector == null)
|
|
129
|
+
return null;
|
|
130
|
+
return {
|
|
131
|
+
fetchSpec: selector.normalized,
|
|
132
|
+
name: pkgName,
|
|
133
|
+
type: selector.type,
|
|
134
|
+
registryName,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
55
137
|
//# sourceMappingURL=parseBareSpecifier.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/resolving.npm-resolver",
|
|
3
|
-
"version": "1101.0
|
|
3
|
+
"version": "1101.1.0",
|
|
4
4
|
"description": "Resolver for npm-hosted packages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -28,38 +28,38 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@zkochan/retry": "^0.2.0",
|
|
30
30
|
"encode-registry": "^3.0.1",
|
|
31
|
-
"lru-cache": "^11.
|
|
31
|
+
"lru-cache": "^11.2.7",
|
|
32
32
|
"normalize-path": "^3.0.0",
|
|
33
|
-
"p-limit": "^7.
|
|
33
|
+
"p-limit": "^7.1.0",
|
|
34
34
|
"p-memoize": "8.0.0",
|
|
35
|
-
"parse-npm-tarball-url": "^
|
|
35
|
+
"parse-npm-tarball-url": "^5.0.0",
|
|
36
36
|
"path-temp": "^3.0.0",
|
|
37
37
|
"ramda": "npm:@pnpm/ramda@0.28.1",
|
|
38
38
|
"rename-overwrite": "^7.0.1",
|
|
39
|
-
"semver": "^7.7.
|
|
39
|
+
"semver": "^7.7.2",
|
|
40
40
|
"semver-utils": "^1.1.4",
|
|
41
41
|
"ssri": "13.0.1",
|
|
42
42
|
"version-selector-type": "^3.0.0",
|
|
43
|
-
"@pnpm/config.pick-registry-for-package": "1100.0.
|
|
44
|
-
"@pnpm/constants": "1100.0.0",
|
|
45
|
-
"@pnpm/core-loggers": "1100.0.1",
|
|
43
|
+
"@pnpm/config.pick-registry-for-package": "1100.0.3",
|
|
46
44
|
"@pnpm/crypto.hash": "1100.0.1",
|
|
47
45
|
"@pnpm/error": "1100.0.0",
|
|
48
46
|
"@pnpm/fetching.types": "1100.0.1",
|
|
49
|
-
"@pnpm/fs.graceful-fs": "1100.1.0",
|
|
50
47
|
"@pnpm/resolving.jsr-specifier-parser": "1100.0.0",
|
|
51
|
-
"@pnpm/
|
|
52
|
-
"@pnpm/resolving.registry.
|
|
53
|
-
"@pnpm/
|
|
54
|
-
"@pnpm/store.
|
|
55
|
-
"@pnpm/
|
|
56
|
-
"@pnpm/types": "1101.
|
|
48
|
+
"@pnpm/fs.graceful-fs": "1100.1.0",
|
|
49
|
+
"@pnpm/resolving.registry.pkg-metadata-filter": "1100.0.3",
|
|
50
|
+
"@pnpm/store.cafs": "1100.1.3",
|
|
51
|
+
"@pnpm/store.index": "1100.1.0",
|
|
52
|
+
"@pnpm/resolving.registry.types": "1100.0.3",
|
|
53
|
+
"@pnpm/types": "1101.1.0",
|
|
54
|
+
"@pnpm/resolving.resolver-base": "1100.1.3",
|
|
55
|
+
"@pnpm/constants": "1100.0.0",
|
|
57
56
|
"@pnpm/workspace.range-resolver": "1100.0.1",
|
|
58
|
-
"@pnpm/workspace.spec-parser": "1100.0.0"
|
|
57
|
+
"@pnpm/workspace.spec-parser": "1100.0.0",
|
|
58
|
+
"@pnpm/core-loggers": "1100.0.2"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
|
-
"@pnpm/logger": "
|
|
62
|
-
"@pnpm/worker": "^1100.1.
|
|
61
|
+
"@pnpm/logger": ">=1001.0.0 <1002.0.0",
|
|
62
|
+
"@pnpm/worker": "^1100.1.4"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@jest/globals": "30.3.0",
|
|
@@ -69,12 +69,12 @@
|
|
|
69
69
|
"@types/ssri": "^7.1.5",
|
|
70
70
|
"load-json-file": "^7.0.1",
|
|
71
71
|
"tempy": "3.0.0",
|
|
72
|
-
"@pnpm/config.version-policy": "1100.0.
|
|
72
|
+
"@pnpm/config.version-policy": "1100.0.3",
|
|
73
73
|
"@pnpm/logger": "1100.0.0",
|
|
74
|
-
"@pnpm/
|
|
75
|
-
"@pnpm/
|
|
74
|
+
"@pnpm/resolving.npm-resolver": "1101.1.0",
|
|
75
|
+
"@pnpm/network.fetch": "1100.0.3",
|
|
76
76
|
"@pnpm/test-fixtures": "1100.0.0",
|
|
77
|
-
"@pnpm/testing.mock-agent": "1100.0.
|
|
77
|
+
"@pnpm/testing.mock-agent": "1100.0.3"
|
|
78
78
|
},
|
|
79
79
|
"engines": {
|
|
80
80
|
"node": ">=22.13"
|