Skip to content

Commit 4d6d4d3

Browse files
committed
fix(findNvim): handle invalid versions
Problem: parseVersion() does not handle invalid version strings. For example if findNvim() passes a partial or invalid version string, or undefined. Solution: - If compareVersions() arg 1 is invalid, throw an error. - If compareVersions() arg 2 is invalid, treat it as "older"/"less".
1 parent 0b2008a commit 4d6d4d3

File tree

2 files changed

+27
-4
lines changed

2 files changed

+27
-4
lines changed

packages/neovim/src/utils/findNvim.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ describe('findNvim', () => {
2121
afterAll(() => {
2222
rmSync(testDir, { recursive: true, force: true });
2323
});
24+
2425
it('parseVersion()', () => {
2526
expect(parseVersion('0.5.0-dev+1357-g192f89ea1')).toEqual([
2627
0,
@@ -74,6 +75,18 @@ describe('findNvim', () => {
7475
'0.3.0-dev-658+g06694203e-Homebrew'
7576
)
7677
).toBe(1);
78+
79+
// Failure modes:
80+
expect(compareVersions('0.3.0', 'nonsense')).toBe(1);
81+
expect(() => compareVersions('nonsense', '0.3.0')).toThrow(
82+
'Invalid version: "nonsense"'
83+
);
84+
expect(() => compareVersions('nonsense', 'nonsense')).toThrow(
85+
'Invalid version: "nonsense"'
86+
);
87+
expect(() => compareVersions(undefined, undefined)).toThrow(
88+
'Invalid version format: not a string'
89+
);
7790
});
7891

7992
/** Asserts that >=1 nvim binaries were found. */

packages/neovim/src/utils/findNvim.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ function parseVersion(version: string): (number | string)[] | undefined {
8383
}
8484

8585
const [, major, minor, patch, prerelease] = match;
86+
if (major === undefined || minor === undefined || patch === undefined) {
87+
throw new TypeError(`Invalid version string: "${version}"`);
88+
}
8689
const majorNumber = Number(major);
8790
const minorNumber = Number(minor);
8891
const patchNumber = Number(patch);
@@ -114,11 +117,17 @@ function parseVersion(version: string): (number | string)[] | undefined {
114117
function compareVersions(a: string, b: string): number {
115118
const versionA = parseVersion(a);
116119
const versionB = parseVersion(b);
117-
const length = Math.min(versionA?.length ?? 0, versionB?.length ?? 0);
120+
if (versionA === undefined) {
121+
throw new TypeError(`Invalid version: "${a}"`);
122+
}
123+
if (versionB === undefined) {
124+
return 1;
125+
}
118126

127+
const length = Math.min(versionA.length, versionB.length);
119128
for (let i = 0; i < length; i = i + 1) {
120-
const partA = versionA?.[i] ?? 0;
121-
const partB = versionB?.[i] ?? 0;
129+
const partA = versionA[i] ?? 0;
130+
const partB = versionB[i] ?? 0;
122131
if (partA < partB) {
123132
return -1;
124133
}
@@ -127,7 +136,7 @@ function compareVersions(a: string, b: string): number {
127136
}
128137
}
129138

130-
if ((versionB?.length ?? 0) > (versionA?.length ?? 0)) {
139+
if (versionB.length > versionA.length) {
131140
return -1;
132141
}
133142

@@ -209,6 +218,7 @@ export function findNvim(opt: FindNvimOptions = {}): Readonly<FindNvimResult> {
209218
if (existsSync(nvimPath) || normalizedPathsFromUser.includes(nvimPath)) {
210219
try {
211220
accessSync(nvimPath, constants.X_OK);
221+
// TODO: fallback to `echo 'print(vim.version())' | nvim -l -` if parsing --version fails.
212222
const nvimVersionFull = execFileSync(nvimPath, [
213223
'--version',
214224
]).toString();

0 commit comments

Comments
 (0)