diff --git a/lib/analyzeFiles/findRequires/javascriptRequireFinder.js b/lib/analyzeFiles/findRequires/javascriptRequireFinder.js index 95ff016..14e5180 100644 --- a/lib/analyzeFiles/findRequires/javascriptRequireFinder.js +++ b/lib/analyzeFiles/findRequires/javascriptRequireFinder.js @@ -3,6 +3,37 @@ var requirePathFilter = require('./requirePathFilter'); module.exports = function(contents, filename) { contents = handleShebang(contents); + try { + return babylonFinder(contents); + } + catch (err) { + //fall back to stupid/fragile regex parsing + return regexFinder(contents); + } +}; + +function regexFinder(contents) { + var lines = contents.split('\n'); + var requires = []; + var importRegex = /(import .+? from|require\s*\()\s*['"`]/g; + lines.map(function(line, i) { + var result = importRegex.exec(line); + if (!result) return; + var location = result.index + result[0].length; + var requirePath = line.substring(location).split(/['"`]/)[0]; + requires.push({ + path: requirePath, + loc: { + line: i, + start: location, + length: requirePath.length + } + }); + }); + return requires; +} + +function babylonFinder(contents) { // kitchen-sink approach, since we just want to find requires/imports/etc. var bbl = babylon.parse(contents, {sourceType: 'module', plugins: [ @@ -24,12 +55,13 @@ module.exports = function(contents, filename) { var requires = []; scan(bbl.tokens, requires); return requires; -}; +} function scan(tokens, requires, index) { for(var i = 0; i < tokens.length; i++) { var token = tokens[i]; - if (token.type.keyword === 'import' || (token.type.label === 'name' && token.value === 'require')) { + var type = token.type; + if (type.keyword === 'import' || (type.label === 'name' && token.value === 'require')) { while ( tokens[i] && tokens[i].type && tokens[i].type.label !== 'string' && i < tokens.length) { i++; } addIfMatch(requires, tokens[i]); diff --git a/test/findRequires_spec.js b/test/findRequires_spec.js index 166cadd..404a18c 100644 --- a/test/findRequires_spec.js +++ b/test/findRequires_spec.js @@ -51,6 +51,8 @@ export const fetchLookup = query => expect(requires[0].path).to.equal('./foo'); }); + + }); describe('with javascript', () => { @@ -65,6 +67,27 @@ export const fetchLookup = query => expect(requires[0].path).to.equal('./foo'); }); + it('handles import in a file that babylon can\'t fully parse', () => { + const code = `import * as x from './y'; +let foo; +foo = foo || () => {}; //babylon can't handle this for some reason + `; + const requires = findRequires('js', code); + expect(requires.length).to.eql(1); + expect(requires[0].path).to.equal('./y'); + }); + + it('handles require in a file that babylon can\'t fully parse', () => { + const code = `const x = require('./y'); +let foo; +foo = foo || () => {}; //babylon can't handle this for some reason + `; + const requires = findRequires('js', code); + expect(requires.length).to.eql(1); + expect(requires[0].path).to.equal('./y'); + }); + + it('handles a shebanged javascript file', () => { const code = "#! /usr/bin/env node\nvar foo = require( './foo' );\n"; const requires = findRequires('js', code);