Skip to content

Commit 11738d4

Browse files
author
Nicholas Pape
authored
Fix issue with PNPM when reading shrinkwrap version for scoped peer dependencies (microsoft#488)
* Re-write some logic to make it more straightforward * Ensure that we properly handle cases where we have a scoped peer dependency
1 parent 49a31bb commit 11738d4

File tree

3 files changed

+75
-8
lines changed

3 files changed

+75
-8
lines changed

apps/rush-lib/src/cli/logic/pnpm/PnpmShrinkwrapFile.ts

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,37 @@ interface IShrinkwrapYaml {
5959
specifiers: { [dependency: string]: string };
6060
}
6161

62+
export function extractVersionFromPnpmVersionSpecifier(version: string): string | undefined {
63+
let extractedVersion: string | undefined = undefined;
64+
65+
if (!version) {
66+
return undefined;
67+
}
68+
69+
const versionParts: string[] = version.split('/');
70+
71+
// it had no slashes, so we know it is a version like "0.0.5"
72+
if (versionParts.length === 1) {
73+
extractedVersion = version; // e.g. "0.0.5"
74+
} else {
75+
const isScoped: boolean = versionParts[1].indexOf('@') === 0;
76+
77+
// e.g. "/gulp-karma/0.0.5/karma@0.13.22"
78+
// if it has 4 parts, then it should be unscoped
79+
if (versionParts.length === 4 && !isScoped) {
80+
extractedVersion = versionParts[2]; // e.g. "0.0.5"
81+
}
82+
83+
// e.g. "/@ms/sp-client-utilities/3.1.1/foo@13.1.0"
84+
// if it has 5 parts, it should be scoped
85+
if (versionParts.length === 5 && isScoped) {
86+
extractedVersion = versionParts[3]; // e.g. "3.1.1"
87+
}
88+
}
89+
90+
return extractedVersion;
91+
}
92+
6293
export class PnpmShrinkwrapFile extends BaseShrinkwrapFile {
6394
private _shrinkwrapJson: IShrinkwrapYaml;
6495

@@ -123,19 +154,23 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile {
123154
// version will be either:
124155
// A - the version (e.g. "0.0.5")
125156
// B - a peer dep version (e.g. "/gulp-karma/0.0.5/karma@0.13.22"
157+
// or "/@ms/sp-client-utilities/3.1.1/foo@13.1.0"
126158
// or "/sinon-chai/2.8.0/chai@3.5.0+sinon@1.17.7")
127159

128160
// check to see if this is the special style of specifiers
129-
// e.g.: "/gulp-karma/0.0.5/karma@0.13.22"
130-
// split it by forward slashes, then grab the second group
161+
// e.g.: "/gulp-karma/0.0.5/karma@0.13.22" or
162+
// or "/@ms/sp-client-utilities/3.1.1/foo@13.1.0"
163+
// split it by forward slashes, then grab the second group (or the 3rd, if the package name is scoped)
131164
// if the second group doesn't exist, return the version directly
132165
if (version) {
133-
const versionParts: string[] = version.split('/');
134-
if (versionParts.length !== 1 && versionParts.length !== 4) {
166+
const extractedVersion: string | undefined = extractVersionFromPnpmVersionSpecifier(version);
167+
168+
if (!extractedVersion) {
135169
throw new Error(`Cannot parse pnpm shrinkwrap version specifier: `
136170
+ `"${version}" for "${dependencyName}"`);
137171
}
138-
return versionParts[2] || version;
172+
173+
return extractedVersion;
139174
} else {
140175
return undefined;
141176
}

apps/rush-lib/src/cli/logic/test/ShrinkwrapFile.test.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as path from 'path';
66

77
import { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile';
88
import { ShrinkwrapFileFactory } from '../ShrinkwrapFileFactory';
9+
import { extractVersionFromPnpmVersionSpecifier } from '../pnpm/PnpmShrinkwrapFile';
910

1011
describe('npm ShrinkwrapFile', () => {
1112
const filename: string = path.resolve(path.join(__dirname, './shrinkwrapFile/npm-shrinkwrap.json'));
@@ -30,9 +31,9 @@ describe('npm ShrinkwrapFile', () => {
3031
});
3132

3233
describe('pnpm ShrinkwrapFile', () => {
33-
const filename: string = path.resolve(path.join(
34-
__dirname, '../../../../src/cli/logic/test/shrinkwrapFile/shrinkwrap.yaml'));
35-
const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!;
34+
const filename: string = path.resolve(path.join(
35+
__dirname, '../../../../src/cli/logic/test/shrinkwrapFile/shrinkwrap.yaml'));
36+
const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!;
3637

3738
it('verifies root-level dependency', () => {
3839
assert.isTrue(shrinkwrapFile.hasCompatibleTopLevelDependency('jquery', '>=2.0.0 <3.0.0'));
@@ -51,3 +52,23 @@ describe('pnpm ShrinkwrapFile', () => {
5152
assert.deepEqual(tempProjectNames, ['@rush-temp/project1', '@rush-temp/project2']);
5253
});
5354
});
55+
56+
describe('extractVersionFromPnpmVersionSpecifier', () => {
57+
it('extracts a simple version with no slashes', () => {
58+
assert.equal(extractVersionFromPnpmVersionSpecifier('0.0.5'), '0.0.5');
59+
});
60+
it('extracts an unscoped peer dep', () => {
61+
assert.equal(extractVersionFromPnpmVersionSpecifier('/gulp-karma/0.0.5/karma@0.13.22'), '0.0.5');
62+
});
63+
it('extracts a scoped peer dep', () => {
64+
assert.equal(extractVersionFromPnpmVersionSpecifier('/@ms/sp-client-utilities/3.1.1/foo@13.1.0'), '3.1.1');
65+
});
66+
it('handles bad cases', () => {
67+
assert.equal(extractVersionFromPnpmVersionSpecifier('/foo/gulp-karma/0.0.5/karma@0.13.22'), undefined);
68+
assert.equal(extractVersionFromPnpmVersionSpecifier('/@ms/3.1.1/foo@13.1.0'), undefined);
69+
assert.equal(extractVersionFromPnpmVersionSpecifier(''), undefined);
70+
assert.equal(extractVersionFromPnpmVersionSpecifier('/'), undefined);
71+
assert.equal(extractVersionFromPnpmVersionSpecifier('//'), undefined);
72+
assert.equal(extractVersionFromPnpmVersionSpecifier('/@/'), undefined);
73+
});
74+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"comment": "Fix an issue when parsing scoped peer dependencies in the pnpm shrinkwrap file",
5+
"packageName": "@microsoft/rush",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@microsoft/rush",
10+
"email": "nickpape-msft@users.noreply.github.com"
11+
}

0 commit comments

Comments
 (0)