Skip to content

Commit

Permalink
refactor: make PathHelper bullet proof
Browse files Browse the repository at this point in the history
  • Loading branch information
NicoVogel committed Oct 25, 2022
1 parent 6b3fe9d commit f19727a
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 111 deletions.
240 changes: 136 additions & 104 deletions libs/vscode/nx-project-view/src/lib/views/nx-profile-util.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,67 +2,145 @@ import * as win32Path from 'path/win32';
import * as posixPath from 'path/posix';
import { PathHelper } from './nx-project-util';

const dirsWindowsTests = (ph: PathHelper) => {
it('only root results in empty output', () => {
const input = 'C:\\';
const output: string[] = [];
expect(ph.dirs(input)).toEqual(output);
});
it('absolute path results in array of folder names', () => {
const input = 'C:\\Users\\foo\\nx-console';
const output: string[] = ['Users', 'foo', 'nx-console'];
expect(ph.dirs(input)).toEqual(output);
});
it('absolute path (depth 1) results in array of folder names', () => {
const input = 'C:\\Users';
const output: string[] = ['Users'];
expect(ph.dirs(input)).toEqual(output);
});
it('relative path results in array of folder names', () => {
const input = 'Users\\foo\\nx-console';
const output: string[] = ['Users', 'foo', 'nx-console'];
expect(ph.dirs(input)).toEqual(output);
});
it('relative path (depth 1) results in array of folder names', () => {
const input = 'Users';
const output: string[] = ['Users'];
expect(ph.dirs(input)).toEqual(output);
});
};

const dirsLinuxTests = (ph: PathHelper) => {
it('only root results in empty output', () => {
const input = '/';
const output: string[] = [];
expect(ph.dirs(input)).toEqual(output);
});
it('absolute path results in array of folder names', () => {
const input = '/home/foo/nx-console';
const output: string[] = ['home', 'foo', 'nx-console'];
expect(ph.dirs(input)).toEqual(output);
});
it('absolute path (depth 1) results in array of folder names', () => {
const input = '/home';
const output: string[] = ['home'];
expect(ph.dirs(input)).toEqual(output);
});
it('relative path results in array of folder names', () => {
const input = 'home/foo/nx-console';
const output: string[] = ['home', 'foo', 'nx-console'];
expect(ph.dirs(input)).toEqual(output);
});
it('relative path (depth 1) results in array of folder names', () => {
const input = 'home';
const output: string[] = ['home'];
expect(ph.dirs(input)).toEqual(output);
});
};

const createPathPermutationsWindowsTests = (ph: PathHelper) => {
it('only root results in empty output', () => {
const input = 'C:\\';
const output: string[] = [];
expect(ph.createPathPermutations(input)).toEqual(output);
});
it('absolute path results in folder permutations', () => {
const input = 'C:\\Users\\foo\\nx-console';
const output: string[] = [
'C:\\Users\\foo\\nx-console',
'C:\\Users\\foo',
'C:\\Users',
];
expect(ph.createPathPermutations(input)).toEqual(output);
});
it('absolute path (depth 1) results in folder permutation', () => {
const input = 'C:\\Users';
const output: string[] = ['C:\\Users'];
expect(ph.createPathPermutations(input)).toEqual(output);
});
it('relative path results in array in folder permutation', () => {
const input = 'Users\\foo\\nx-console';
const output: string[] = ['Users\\foo\\nx-console', 'Users\\foo', 'Users'];
expect(ph.createPathPermutations(input)).toEqual(output);
});
it('relative path (depth 1) results in array in folder permutation', () => {
const input = 'Users';
const output: string[] = ['Users'];
expect(ph.createPathPermutations(input)).toEqual(output);
});
};

const createPathPermutationsLinuxTests = (ph: PathHelper) => {
it('only root results in empty output', () => {
const input = '/';
const output: string[] = [];
expect(ph.createPathPermutations(input)).toEqual(output);
});
it('absolute path results in array in folder permutation', () => {
const input = '/home/foo/nx-console';
const output: string[] = ['/home/foo/nx-console', '/home/foo', '/home'];
expect(ph.createPathPermutations(input)).toEqual(output);
});
it('absolute path (depth 1) results in array in folder permutation', () => {
const input = '/home';
const output: string[] = ['/home'];
expect(ph.createPathPermutations(input)).toEqual(output);
});
it('relative path results in array in folder permutation', () => {
const input = 'home/foo/nx-console';
const output: string[] = ['home/foo/nx-console', 'home/foo', 'home'];
expect(ph.createPathPermutations(input)).toEqual(output);
});
it('relative path (depth 1) results in array in folder permutation', () => {
const input = 'home';
const output: string[] = ['home'];
expect(ph.createPathPermutations(input)).toEqual(output);
});
};

describe('Project View: PathHelper', () => {
describe('dirs', () => {
it('empty input results in empty output', () => {
const input = '';
const output: string[] = [];
expect(new PathHelper().dirs(input)).toEqual(output);
});

describe('windows', () => {
const ph = new PathHelper(win32Path);
it('only root results in empty output', () => {
const input = 'C:\\';
const output: string[] = [];
expect(ph.dirs(input)).toEqual(output);
});
it('absolute path results in array of folder names', () => {
const input = 'C:\\Users\\foo\\nx-console';
const output: string[] = ['Users', 'foo', 'nx-console'];
expect(ph.dirs(input)).toEqual(output);
});
it('absolute path (depth 1) results in array of folder names', () => {
const input = 'C:\\Users';
const output: string[] = ['Users'];
expect(ph.dirs(input)).toEqual(output);
});
it('relative path results in array of folder names', () => {
const input = 'Users\\foo\\nx-console';
const output: string[] = ['Users', 'foo', 'nx-console'];
expect(ph.dirs(input)).toEqual(output);
});
it('relative path (depth 1) results in array of folder names', () => {
const input = 'Users';
const output: string[] = ['Users'];
expect(ph.dirs(input)).toEqual(output);
dirsWindowsTests(ph);

describe('with linux paths', () => {
dirsLinuxTests(ph);
});
});

describe('linux', () => {
const ph = new PathHelper(posixPath);
it('only root results in empty output', () => {
const input = '/';
const output: string[] = [];
expect(ph.dirs(input)).toEqual(output);
});
it('absolute path results in array of folder names', () => {
const input = '/home/foo/nx-console';
const output: string[] = ['home', 'foo', 'nx-console'];
expect(ph.dirs(input)).toEqual(output);
});
it('absolute path (depth 1) results in array of folder names', () => {
const input = '/home';
const output: string[] = ['home'];
expect(ph.dirs(input)).toEqual(output);
});
it('relative path results in array of folder names', () => {
const input = 'home/foo/nx-console';
const output: string[] = ['home', 'foo', 'nx-console'];
expect(ph.dirs(input)).toEqual(output);
});
it('relative path (depth 1) results in array of folder names', () => {
const input = 'home';
const output: string[] = ['home'];
expect(ph.dirs(input)).toEqual(output);
dirsLinuxTests(ph);

describe('with windows paths', () => {
dirsWindowsTests(ph);
});
});
});
Expand All @@ -72,68 +150,22 @@ describe('Project View: PathHelper', () => {
const output: string[] = [];
expect(new PathHelper().createPathPermutations(input)).toEqual(output);
});

describe('windows', () => {
const ph = new PathHelper(win32Path);
it('only root results in empty output', () => {
const input = 'C:\\';
const output: string[] = [];
expect(ph.createPathPermutations(input)).toEqual(output);
});
it('absolute path results in folder permutations', () => {
const input = 'C:\\Users\\foo\\nx-console';
const output: string[] = [
'C:\\Users\\foo\\nx-console',
'C:\\Users\\foo',
'C:\\Users',
];
expect(ph.createPathPermutations(input)).toEqual(output);
});
it('absolute path (depth 1) results in folder permutation', () => {
const input = 'C:\\Users';
const output: string[] = ['C:\\Users'];
expect(ph.createPathPermutations(input)).toEqual(output);
});
it('relative path results in array in folder permutation', () => {
const input = 'Users\\foo\\nx-console';
const output: string[] = [
'Users\\foo\\nx-console',
'Users\\foo',
'Users',
];
expect(ph.createPathPermutations(input)).toEqual(output);
});
it('relative path (depth 1) results in array in folder permutation', () => {
const input = 'Users';
const output: string[] = ['Users'];
expect(ph.createPathPermutations(input)).toEqual(output);
createPathPermutationsWindowsTests(ph);

describe('with linux paths', () => {
createPathPermutationsLinuxTests(ph);
});
});

describe('linux', () => {
const ph = new PathHelper(posixPath);
it('only root results in empty output', () => {
const input = '/';
const output: string[] = [];
expect(ph.createPathPermutations(input)).toEqual(output);
});
it('absolute path results in array in folder permutation', () => {
const input = '/home/foo/nx-console';
const output: string[] = ['/home/foo/nx-console', '/home/foo', '/home'];
expect(ph.createPathPermutations(input)).toEqual(output);
});
it('absolute path (depth 1) results in array in folder permutation', () => {
const input = '/home';
const output: string[] = ['/home'];
expect(ph.createPathPermutations(input)).toEqual(output);
});
it('relative path results in array in folder permutation', () => {
const input = 'home/foo/nx-console';
const output: string[] = ['home/foo/nx-console', 'home/foo', 'home'];
expect(ph.createPathPermutations(input)).toEqual(output);
});
it('relative path (depth 1) results in array in folder permutation', () => {
const input = 'home';
const output: string[] = ['home'];
expect(ph.createPathPermutations(input)).toEqual(output);
createPathPermutationsLinuxTests(ph);

describe('with windows paths', () => {
createPathPermutationsWindowsTests(ph);
});
});
});
Expand Down
28 changes: 21 additions & 7 deletions libs/vscode/nx-project-view/src/lib/views/nx-project-util.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import path = require('node:path');
import * as path from 'node:path';
import * as win32Path from 'path/win32';
import * as posixPath from 'path/posix';

export function isDefined<T>(val?: T): val is T {
return !!val;
Expand All @@ -8,7 +10,11 @@ export class PathHelper {
constructor(private pathApi: typeof path = path) {}

detailedDirs(val: string) {
if (!val) return [[] as string[], ''] as const;
if (!val) return [[] as string[], '', this.pathApi] as const;

const oppositeApi = this.getOppositeApi();
const api = val.includes(oppositeApi.sep) ? oppositeApi : this.pathApi;

/**
* @example windows:
* path.parse('C:\\Users\\foo\\nx-console')
Expand All @@ -18,15 +24,16 @@ export class PathHelper {
* path.parse('/home/foo/nx-console')
* { root: '/', dir: '/home/foo', base: 'nx-console', ext: '', name: 'nx-console' }
*/
const { root, dir, base } = this.pathApi.parse(val);
const { root, dir, base } = api.parse(val);
const dirWithoutRoot = root ? dir.slice(root.length) : dir;
const dirs = dirWithoutRoot ? dirWithoutRoot.split(this.pathApi.sep) : [];
const dirs = dirWithoutRoot ? dirWithoutRoot.split(api.sep) : [];
if (base) {
dirs.push(base);
}

return [dirs, root] as const;
return [dirs, root, api] as const;
}

dirs(val: string) {
return this.detailedDirs(val)[0];
}
Expand Down Expand Up @@ -54,13 +61,20 @@ export class PathHelper {
* ]
*/
createPathPermutations(dir: string) {
const [dirs, root] = this.detailedDirs(dir);
const [dirs, root, api] = this.detailedDirs(dir);
const parts = dirs.reverse();
const permutations: string[] = [];
for (let i = 0; i < parts.length; i++) {
const partialDir = this.pathApi.join(root, ...parts.slice(i).reverse());
const partialDir = api.join(root, ...parts.slice(i).reverse());
permutations.push(partialDir);
}
return permutations;
}

private getOppositeApi() {
if (this.pathApi.sep === win32Path.sep) {
return posixPath;
}
return win32Path;
}
}

0 comments on commit f19727a

Please sign in to comment.