Skip to content

Commit

Permalink
Merge pull request #282 from Galooshi/windows-support
Browse files Browse the repository at this point in the history
Windows support
  • Loading branch information
lencioni committed May 28, 2016
2 parents d93f7e0 + bc69bf8 commit 0994bc3
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 94 deletions.
174 changes: 96 additions & 78 deletions lib/__tests__/findMatchingFiles-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,103 +6,121 @@ import rimraf from 'rimraf';

import findMatchingFiles from '../findMatchingFiles';

describe('findMatchingFiles', () => {
const tmpDir = './tmp-findMatchingFiles';
let subject;
let word;
let existingFiles;
let lookupPath;

beforeEach(() => {
fs.mkdirSync(tmpDir);
word = 'foo';
existingFiles = [];
lookupPath = tmpDir;

subject = () => {
existingFiles.forEach((file) => {
const fullPath = `${tmpDir}/${file}`;
mkdirp.sync(path.dirname(fullPath));
fs.closeSync(fs.openSync(fullPath, 'w')); // create empty file
['node', 'find'].forEach((finder) => {
describe(`findMatchingFiles finder: ${finder}`, () => {
const tmpDir = './tmp-findMatchingFiles';
let subject;
let word;
let existingFiles;
let lookupPath;
let originalPlatform;

if (finder === 'node') {
beforeEach(() => {
originalPlatform = process.platform;
Object.defineProperty(process, 'platform', {
value: 'win32',
});
});

return findMatchingFiles(lookupPath, word);
};
});

afterEach((done) => {
rimraf(tmpDir, done);
});
afterEach(() => {
Object.defineProperty(process, 'platform', {
value: originalPlatform,
});
});
}

describe('when there are no matching files', () => {
beforeEach(() => {
existingFiles = [
'car/door.js',
];
fs.mkdirSync(tmpDir);
word = 'foo';
existingFiles = [];
lookupPath = tmpDir;

subject = () => {
existingFiles.forEach((file) => {
const fullPath = `${tmpDir}/${file}`;
mkdirp.sync(path.dirname(fullPath));
fs.closeSync(fs.openSync(fullPath, 'w')); // create empty file
});

return findMatchingFiles(lookupPath, word, finder);
};
});

it('returns an empty array', () => {
expect(subject()).toEqual([]);
afterEach((done) => {
rimraf(tmpDir, done);
});
});

describe('when the lookup path is empty', () => {
beforeEach(() => {
lookupPath = '';
});
describe('when there are no matching files', () => {
beforeEach(() => {
existingFiles = [
'car/door.js',
];
});

it('throws an error', () => {
expect(subject).toThrowError(/empty/);
it('returns an empty array', () => {
expect(subject()).toEqual([]);
});
});
});

describe('when there are multiple files matching word', () => {
beforeEach(() => {
existingFiles = [
'bar/foo.js',
'car/Foo.jsx',
'tzar/foo/index.js',
'car/door.js',
'har-har/foo/package.json',
'car/door/index.js',
'react/foo/index.jsx',
];
});
describe('when the lookup path is empty', () => {
beforeEach(() => {
lookupPath = '';
});

it('returns the matching files', () => {
expect(subject().sort()).toEqual([
`${tmpDir}/bar/foo.js`,
`${tmpDir}/car/Foo.jsx`,
`${tmpDir}/har-har/foo/package.json`,
`${tmpDir}/react/foo/index.jsx`,
`${tmpDir}/tzar/foo/index.js`,
]);
it('throws an error', () => {
expect(subject).toThrowError(/empty/);
});
});
});

describe('when the word has camelCase', () => {
beforeEach(() => {
word = 'FooBar';
});
describe('when there are multiple files matching word', () => {
beforeEach(() => {
existingFiles = [
'bar/foo.js',
'car/Foo.jsx',
'tzar/foo/index.js',
'car/door.js',
'har-har/foo/package.json',
'car/door/index.js',
'react/foo/index.jsx',
];
});

it('matches snake_case names', () => {
existingFiles = ['foo_bar.js'];
expect(subject()).toEqual([`${tmpDir}/foo_bar.js`]);
it('returns the matching files', () => {
expect(subject().sort()).toEqual([
`${tmpDir}/bar/foo.js`,
`${tmpDir}/car/Foo.jsx`,
`${tmpDir}/har-har/foo/package.json`,
`${tmpDir}/react/foo/index.jsx`,
`${tmpDir}/tzar/foo/index.js`,
]);
});
});

it('matches camelCase names', () => {
existingFiles = ['fooBar.js'];
expect(subject()).toEqual([`${tmpDir}/fooBar.js`]);
});
describe('when the word has camelCase', () => {
beforeEach(() => {
word = 'FooBar';
});

it('matches folder + file name', () => {
existingFiles = ['foo/Bar.js'];
expect(subject()).toEqual([`${tmpDir}/foo/Bar.js`]);
});
it('matches snake_case names', () => {
existingFiles = ['foo_bar.js'];
expect(subject()).toEqual([`${tmpDir}/foo_bar.js`]);
});

it('matches camelCase names', () => {
existingFiles = ['fooBar.js'];
expect(subject()).toEqual([`${tmpDir}/fooBar.js`]);
});

it('matches plural folder name + file name', () => {
existingFiles = ['foos/Bar.js'];
expect(subject()).toEqual([`${tmpDir}/foos/Bar.js`]);
it('matches folder + file name', () => {
existingFiles = ['foo/Bar.js'];
expect(subject()).toEqual([`${tmpDir}/foo/Bar.js`]);
});

it('matches plural folder name + file name', () => {
existingFiles = ['foos/Bar.js'];
expect(subject()).toEqual([`${tmpDir}/foos/Bar.js`]);
});
});
});
});
52 changes: 36 additions & 16 deletions lib/findMatchingFiles.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,20 @@
// @flow

import childProcess from 'child_process';
import glob from 'glob';

import formattedToRegex from './formattedToRegex';

/**
* Finds files from the local file system matching the variable name.
*/
export default function findMatchingFiles(
function findMatchingFilesWithFind(
lookupPath: string,
variableName: string
validFilesRegex: string
): Array<string> {
if (lookupPath === '') {
// If lookupPath is an empty string, the `find` command will not work
// as desired so we bail early.
throw new Error(`lookup path cannot be empty (${lookupPath})`);
}

const formattedVarName = formattedToRegex(variableName);
const egrepCommand =
`egrep -i \"(/|^)${formattedVarName}(/index)?(/package)?\.js.*\"`;

const findCommand = [
`find ${lookupPath}`,
'-name "**.js*"',
'-not -path "./node_modules/*"',
].join(' ');
const command = `${findCommand} | ${egrepCommand}`;
const command = `${findCommand} | egrep -i \"${validFilesRegex}\"`;

// TODO switch to spawn so we can start processing the stream as it comes
// in.
Expand All @@ -45,3 +33,35 @@ export default function findMatchingFiles(
// Filter out empty lines before returning
return out.split('\n').filter((file: string): boolean => !!file);
}

function findMatchingFilesWithNode(
lookupPath: string,
validFilesRegex: string
): Array<string> {
return glob.sync(`${lookupPath}/**/*.js*`, {
ignore: './node_modules/**/*',
}).filter((filePath: string): bool =>
new RegExp(validFilesRegex, 'i').test(filePath));
}

/**
* Finds files from the local file system matching the variable name.
*/
export default function findMatchingFiles(
lookupPath: string,
variableName: string
): Array<string> {
if (lookupPath === '') {
// If lookupPath is an empty string, the `find` command will not work
// as desired so we bail early.
throw new Error(`lookup path cannot be empty (${lookupPath})`);
}

const formattedVarName = formattedToRegex(variableName);
const validFilesRegex = `(/|^)${formattedVarName}(/index)?(/package)?\\.js.*`;

if (/^win/.test(process.platform)) {
return findMatchingFilesWithNode(lookupPath, validFilesRegex);
}
return findMatchingFilesWithFind(lookupPath, validFilesRegex);
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"StringScanner": "0.0.3",
"commander": "^2.9.0",
"eslint": "^2.8.0",
"glob": "^7.0.3",
"lodash.escaperegexp": "^4.1.1",
"lodash.flattendeep": "^4.1.0",
"lodash.partition": "^4.2.0",
Expand Down

0 comments on commit 0994bc3

Please sign in to comment.