Skip to content

Commit 898f072

Browse files
authored
[3.x] feat: allow npm:name@version dependency redirections in manifest (#158) (#159)
feat: allow `npm:name@version` dependency redirections in manifest (#158)
1 parent 08aa582 commit 898f072

File tree

4 files changed

+57
-6
lines changed

4 files changed

+57
-6
lines changed

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"execa": "^8.0.1",
3333
"pony-cause": "^2.1.9",
3434
"semver": "^7.5.4",
35+
"validate-npm-package-name": "^5.0.0",
3536
"which": "^3.0.0",
3637
"yaml": "^2.2.2",
3738
"yargs": "^17.7.1"
@@ -52,6 +53,7 @@
5253
"@types/node": "^17.0.23",
5354
"@types/prettier": "^2.7.3",
5455
"@types/rimraf": "^4.0.5",
56+
"@types/validate-npm-package-name": "^4.0.2",
5557
"@types/which": "^3.0.0",
5658
"@types/yargs": "^17.0.10",
5759
"@typescript-eslint/eslint-plugin": "^5.62.0",

src/package-manifest.test.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ describe('package-manifest', () => {
6767
b: '^2.0.0',
6868
c: '~4.3.0',
6969
d: 'workspace:^',
70+
e: 'npm:@a/abc@^2.0.0',
7071
},
7172
};
7273
const validated = {
@@ -79,6 +80,7 @@ describe('package-manifest', () => {
7980
b: '^2.0.0',
8081
c: '~4.3.0',
8182
d: 'workspace:^',
83+
e: 'npm:@a/abc@^2.0.0',
8284
},
8385
peerDependencies: {},
8486
};
@@ -315,7 +317,9 @@ describe('package-manifest', () => {
315317
name: 'foo',
316318
version: '1.0.0',
317319
peerDependencies: {
318-
a: 12345,
320+
a: 'npm:@foo',
321+
b: 'npm:foo@',
322+
c: '12345',
319323
},
320324
}),
321325
);

src/package-manifest.ts

+34-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
ManifestDependencyFieldNames as PackageManifestDependenciesFieldNames,
55
} from '@metamask/action-utils';
66
import { isPlainObject } from '@metamask/utils';
7+
import validateNPMPackageName from 'validate-npm-package-name';
78
import { readJsonObjectFile } from './fs.js';
89
import { isTruthyString } from './misc-utils.js';
910
import { semver, SemVer } from './semver.js';
@@ -144,8 +145,10 @@ function isValidPackageManifestVersionField(
144145

145146
/**
146147
* Type guard to ensure that the provided version value is a valid dependency version
147-
* specifier for a package manifest. This function validates both semantic versioning
148-
* ranges and the special 'workspace:^' notation.
148+
* specifier for a package manifest. This function validates:
149+
* semantic versioning ranges
150+
* 'workspace:^' notation
151+
* 'npm:{packageName}:{semverRange}' redirections.
149152
*
150153
* @param version - The value to check.
151154
* @returns `true` if the version is a valid string that either
@@ -155,9 +158,35 @@ function isValidPackageManifestVersionField(
155158
function isValidPackageManifestDependencyValue(
156159
version: unknown,
157160
): version is string {
158-
return (
159-
isValidPackageManifestVersionField(version) || version === 'workspace:^'
160-
);
161+
if (typeof version !== 'string') {
162+
return false;
163+
}
164+
165+
if (
166+
isValidPackageManifestVersionField(version) ||
167+
version === 'workspace:^'
168+
) {
169+
return true;
170+
}
171+
172+
const redirectedDependencyRegexp = /^npm:(.*)@(.*?)$/u;
173+
174+
try {
175+
const redirectedDependencyMatch = redirectedDependencyRegexp.exec(version);
176+
177+
/* istanbul ignore if */
178+
if (!redirectedDependencyMatch) {
179+
return false;
180+
}
181+
182+
const [, redirectedName, redirectedVersion] = redirectedDependencyMatch;
183+
return (
184+
validateNPMPackageName(redirectedName)?.validForOldPackages &&
185+
isValidPackageManifestVersionField(redirectedVersion)
186+
);
187+
} catch (e) /* istanbul ignore next */ {
188+
return false;
189+
}
161190
}
162191

163192
/**

yarn.lock

+16
Original file line numberDiff line numberDiff line change
@@ -2075,6 +2075,7 @@ __metadata:
20752075
"@types/node": ^17.0.23
20762076
"@types/prettier": ^2.7.3
20772077
"@types/rimraf": ^4.0.5
2078+
"@types/validate-npm-package-name": ^4.0.2
20782079
"@types/which": ^3.0.0
20792080
"@types/yargs": ^17.0.10
20802081
"@typescript-eslint/eslint-plugin": ^5.62.0
@@ -2102,6 +2103,7 @@ __metadata:
21022103
stdio-mock: ^1.2.0
21032104
tsx: ^4.6.1
21042105
typescript: ~5.1.6
2106+
validate-npm-package-name: ^5.0.0
21052107
which: ^3.0.0
21062108
yaml: ^2.2.2
21072109
yargs: ^17.7.1
@@ -2547,6 +2549,13 @@ __metadata:
25472549
languageName: node
25482550
linkType: hard
25492551

2552+
"@types/validate-npm-package-name@npm:^4.0.2":
2553+
version: 4.0.2
2554+
resolution: "@types/validate-npm-package-name@npm:4.0.2"
2555+
checksum: 3f35a3cc8ddd919b456843f36d55a4f1df5f03d5d9b6494b4d8f5f3b24e3f24a11c922772d9970a67f1249214da18c157776e9c6d2e72227799459849dfd9c76
2556+
languageName: node
2557+
linkType: hard
2558+
25502559
"@types/which@npm:^3.0.0":
25512560
version: 3.0.0
25522561
resolution: "@types/which@npm:3.0.0"
@@ -7294,6 +7303,13 @@ __metadata:
72947303
languageName: node
72957304
linkType: hard
72967305

7306+
"validate-npm-package-name@npm:^5.0.0":
7307+
version: 5.0.1
7308+
resolution: "validate-npm-package-name@npm:5.0.1"
7309+
checksum: 0d583a1af23aeffea7748742cf22b6802458736fb8b60323ba5949763824d46f796474b0e1b9206beb716f9d75269e19dbd7795d6b038b29d561be95dd827381
7310+
languageName: node
7311+
linkType: hard
7312+
72977313
"walker@npm:^1.0.8":
72987314
version: 1.0.8
72997315
resolution: "walker@npm:1.0.8"

0 commit comments

Comments
 (0)