Skip to content

Commit d10f2e0

Browse files
committed
fixup
1 parent 9b3958b commit d10f2e0

File tree

4 files changed

+62
-32
lines changed

4 files changed

+62
-32
lines changed

src/m365/spfx/commands/project/project-azuredevops-pipeline-add.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ describe(commands.PROJECT_AZUREDEVOPS_PIPELINE_ADD, () => {
185185

186186
sinon.stub(command as any, 'getProjectVersion').returns('');
187187

188-
sinon.stub(fs, 'writeFileSync').throws('error');
188+
sinon.stub(fs, 'writeFileSync').throws(new Error('writeFileSync failed'));
189189

190190
await assert.rejects(command.action(logger, { options: {} } as any),
191191
new CommandError(`Unable to determine the version of the current SharePoint Framework project`));
@@ -215,7 +215,7 @@ describe(commands.PROJECT_AZUREDEVOPS_PIPELINE_ADD, () => {
215215

216216
sinon.stub(command as any, 'getProjectVersion').returns('99.99.99');
217217

218-
sinon.stub(fs, 'writeFileSync').throws('error');
218+
sinon.stub(fs, 'writeFileSync').throws(new Error('writeFileSync failed'));
219219

220220
await assert.rejects(command.action(logger, { options: {} } as any),
221221
new CommandError(`Could not find Node version for 99.99.99 of SharePoint Framework`));
@@ -250,4 +250,4 @@ describe(commands.PROJECT_AZUREDEVOPS_PIPELINE_ADD, () => {
250250
await assert.rejects(command.action(logger, { options: {} } as any),
251251
new CommandError('error'));
252252
});
253-
});
253+
});

src/m365/spfx/commands/project/project-github-workflow-add.spec.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ describe(commands.PROJECT_GITHUB_WORKFLOW_ADD, () => {
186186

187187
sinon.stub(command as any, 'getProjectVersion').returns(undefined);
188188

189-
sinon.stub(fs, 'writeFileSync').throws('error');
189+
sinon.stub(fs, 'writeFileSync').throws(new Error('writeFileSync failed'));
190190

191191
await assert.rejects(command.action(logger, { options: {} }),
192192
new CommandError(`Unable to determine the version of the current SharePoint Framework project`));
@@ -217,7 +217,7 @@ describe(commands.PROJECT_GITHUB_WORKFLOW_ADD, () => {
217217

218218
sinon.stub(command as any, 'getProjectVersion').returns('99.99.99');
219219

220-
sinon.stub(fs, 'writeFileSync').throws('error');
220+
sinon.stub(fs, 'writeFileSync').throws(new Error('writeFileSync failed'));
221221

222222
await assert.rejects(command.action(logger, { options: {} }),
223223
new CommandError(`Could not find Node version for 99.99.99 of SharePoint Framework`));
@@ -247,9 +247,11 @@ describe(commands.PROJECT_GITHUB_WORKFLOW_ADD, () => {
247247

248248
sinon.stub(command as any, 'getProjectVersion').returns('1.21.1');
249249

250-
sinon.stub(fs, 'writeFileSync').callsFake(() => { throw 'error'; });
250+
sinon.stub(fs, 'writeFileSync').callsFake(() => {
251+
throw new Error('writeFileSync failed');
252+
});
251253

252254
await assert.rejects(command.action(logger, { options: {} } as any),
253-
new CommandError('error'));
255+
new CommandError('writeFileSync failed'));
254256
});
255-
});
257+
});

src/utils/spfx.spec.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ describe('utils/spfx', () => {
3030

3131
it('returns correct Node version for a given range', () => {
3232
const version = spfx.getHighestNodeVersion('>=14.0.0 <15.0.0 || >=16.0.0 <17.0.0');
33-
assert.strictEqual(version, '17.0.x');
33+
assert.strictEqual(version, '16.0.0');
3434
});
3535

3636
it('returns correct Node version for a single version', () => {
3737
const version = spfx.getHighestNodeVersion('^10');
38-
assert.strictEqual(version, '10.0.x');
38+
assert.strictEqual(version, '10.x');
3939
});
4040

4141
it('returns correct Node version for a range with multiple versions', () => {
@@ -47,4 +47,9 @@ describe('utils/spfx', () => {
4747
const version = spfx.getHighestNodeVersion('8.1 || 8.2');
4848
assert.strictEqual(version, '8.2.x');
4949
});
50-
});
50+
51+
it('returns highest major for disjoint ranges', () => {
52+
const version = spfx.getHighestNodeVersion('>=16.13.0 <17.0.0 || >=18.17.1 <19.0.0');
53+
assert.strictEqual(version, '18.17.1');
54+
});
55+
});

src/utils/spfx.ts

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { minVersion, SemVer, validRange } from 'semver';
12
import { Project } from '../m365/spfx/commands/project/project-model/index.js';
23

34
export const spfx = {
@@ -17,35 +18,57 @@ export const spfx = {
1718
},
1819

1920
getHighestNodeVersion(versionRange: string): string {
20-
const ranges = versionRange.split('||').map(r => r.trim());
21+
if (!versionRange) {
22+
throw new Error('Node version range was not provided.');
23+
}
2124

22-
const versions = ranges.map(range => {
23-
if (range.includes('<')) {
24-
const upperBound = range.split('<')[1].trim().split(' ')[0];
25-
const parts = upperBound.split('.');
26-
return `${parts[0]}.${parts[1]}`;
25+
const ranges = versionRange
26+
.split('||')
27+
.map(range => range.trim())
28+
.filter(range => range.length > 0);
29+
30+
let highest: { version: SemVer; source: string } | null = null;
31+
32+
for (const range of ranges) {
33+
const normalized = validRange(range);
34+
if (!normalized) {
35+
continue;
2736
}
2837

29-
const cleaned = range.replace(/[\^>=<~]/g, '');
30-
const parts = cleaned.split('.');
38+
const minimum = minVersion(normalized);
39+
if (!minimum) {
40+
continue;
41+
}
3142

32-
if (parts.length >= 2) {
33-
return `${parts[0]}.${parts[1]}`;
43+
if (!highest || minimum.compare(highest.version) > 0) {
44+
highest = {
45+
version: minimum,
46+
source: range
47+
};
3448
}
49+
}
3550

36-
return `${parts[0]}.0`;
37-
});
51+
if (!highest) {
52+
throw new Error(`Unable to resolve the highest Node version for range '${versionRange}'.`);
53+
}
3854

39-
const sorted = versions.sort((a, b) => {
40-
const [aMajor, aMinor] = a.split('.').map(Number);
41-
const [bMajor, bMinor] = b.split('.').map(Number);
55+
const source = highest.source.trim();
56+
const compactSource = source.replace(/\s+/g, '');
57+
const isCaretOrTilde = compactSource.startsWith('^') || compactSource.startsWith('~');
58+
const isSimpleVersion = /^[0-9]+(\.[0-9]+){0,2}$/.test(compactSource);
4259

43-
if (aMajor !== bMajor) {
44-
return bMajor - aMajor;
60+
if (isCaretOrTilde || isSimpleVersion) {
61+
const numeric = isCaretOrTilde ? compactSource.substring(1) : compactSource;
62+
const parts = numeric.split('.').filter(part => part.length > 0);
63+
const { major, minor } = highest.version;
64+
65+
if (parts.length >= 2) {
66+
return `${major}.${parts[1]}.x`;
4567
}
46-
return bMinor - aMinor;
47-
});
4868

49-
return `${sorted[0]}.x`;
69+
return `${major}.x`;
70+
}
71+
72+
return highest.version.version;
5073
}
51-
};
74+
};

0 commit comments

Comments
 (0)