diff --git a/src/api.ts b/src/api.ts index 793434a..7b7e60b 100644 --- a/src/api.ts +++ b/src/api.ts @@ -276,15 +276,13 @@ interface WriteConfig { /** * Explore multiple bundles and write html output to file. * - * @param codePath Path to bundle file or glob matching bundle files - * @param [mapPath] Path to bundle map file + * @param fileTokens List of file paths or glob patterns */ export async function exploreBundlesAndWriteHtml( writeConfig: WriteConfig, - codePath: string, - mapPath?: string + fileTokens: string[] ): Promise { - const bundles = getBundles(codePath, mapPath); + const bundles = getBundles(fileTokens); return exploreBundles(bundles).then(results => { const successResults = results.filter( diff --git a/src/cli.ts b/src/cli.ts index 05a60f9..a475ae7 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -155,7 +155,7 @@ function writeToHtml(html?: string): void { if (require.main === module) { const argv = parseArguments(); - const bundles = getBundles(argv._[0], argv._[1]); + const bundles = getBundles(argv._); if (bundles.length === 0) { throw new Error('No file(s) found'); diff --git a/src/common.ts b/src/common.ts index 79fbc3b..634ff42 100644 --- a/src/common.ts +++ b/src/common.ts @@ -153,29 +153,42 @@ export interface Bundle { mapPath?: string; } +function expandGlob(pattern: string): string[] { + // Make sure pattern match `.map` files as well + if (pattern.endsWith('.js')) { + pattern = `${pattern}?(.map)`; + } + + return glob.sync(pattern); +} + /** - * Expand codePath and mapPath into a list of { codePath, mapPath } pairs - * @see https://github.com/danvk/source-map-explorer/issues/52 - * @param codePath Path to bundle file or glob matching bundle files - * @param [mapPath] Path to bundle map file + * Expands list of file token into a list of { codePath, mapPath } pairs */ -export function getBundles(codePath: string, mapPath?: string): Bundle[] { - if (codePath && mapPath) { - return [ - { - codePath, - mapPath, - }, - ]; - } +export function getBundles(fileTokens: string[]): Bundle[] { + const filenames = fileTokens.reduce((result, filePath) => { + if (glob.hasMagic(filePath)) { + result.push(...expandGlob(filePath)); + } else { + result.push(filePath); + } - const filenames = glob.sync(codePath); - const mapFilenames = glob.sync(codePath + '.map'); + return result; + }, []); + + const codeFilenames: string[] = []; + const mapFilenames: string[] = []; - return filenames - .filter(filename => !filename.endsWith('.map')) - .map(filename => ({ - codePath: filename, - mapPath: mapFilenames.find(mapFilename => mapFilename === `${filename}.map`), - })); + filenames.forEach(filename => { + if (filename.endsWith('.map')) { + mapFilenames.push(filename); + } else { + codeFilenames.push(filename); + } + }); + + return codeFilenames.map(codePath => ({ + codePath, + mapPath: mapFilenames.find(filename => filename === `${codePath}.map`), + })); } diff --git a/tests/api.test.js b/tests/api.test.js index 3dfd372..f3611f3 100644 --- a/tests/api.test.js +++ b/tests/api.test.js @@ -123,7 +123,7 @@ describe('Public API', function() { fileName: 'bundle-out.tmp.html', }; - await exploreBundlesAndWriteHtml(writeConfig, 'data/*.*'); + await exploreBundlesAndWriteHtml(writeConfig, ['data/*.*']); const data = fs.readFileSync(writeConfigToPath(writeConfig), 'utf8'); @@ -135,7 +135,7 @@ describe('Public API', function() { it('should explore multiple bundles and write a html file to current directory if path is undefined in writeConfig', async function() { const writeConfig = { fileName: 'bundle-out.tmp.html' }; - await exploreBundlesAndWriteHtml(writeConfig, 'data/*.*'); + await exploreBundlesAndWriteHtml(writeConfig, ['data/*.*']); const data = fs.readFileSync(writeConfigToPath(writeConfig), 'utf8'); diff --git a/tests/common..test.js b/tests/common..test.js index ad36261..2734b29 100644 --- a/tests/common..test.js +++ b/tests/common..test.js @@ -2,11 +2,11 @@ import { expect } from 'chai'; import { getBundles } from '../src/common'; -describe('getBundles - command line parsing', function() { +describe('getBundles - file tokens parsing', function() { const tests = [ { name: 'should expand glob', - args: ['data/foo.min.js*'], + fileTokens: ['data/foo.min.js*'], expected: [ { codePath: 'data/foo.min.js', @@ -16,7 +16,7 @@ describe('getBundles - command line parsing', function() { }, { name: 'should return one bundle if map file specified', - args: ['foo.min.js', 'foo.min.js.map'], + fileTokens: ['foo.min.js', 'foo.min.js.map'], expected: [ { codePath: 'foo.min.js', @@ -26,7 +26,7 @@ describe('getBundles - command line parsing', function() { }, { name: 'should expand glob into all bundles in directory', - args: ['data/*.*'], + fileTokens: ['data/*.*'], expected: [ { codePath: 'data/foo.1234.js', @@ -47,8 +47,8 @@ describe('getBundles - command line parsing', function() { ], }, { - name: 'should support single file glob', - args: ['data/foo.1*.js'], + name: 'should expand glob including .map files', + fileTokens: ['data/foo.1*.js'], expected: [ { codePath: 'data/foo.1234.js', @@ -56,9 +56,33 @@ describe('getBundles - command line parsing', function() { }, ], }, + { + name: 'should expand glob into code and map files', + fileTokens: ['data/foo.1*.js?(.map)'], + expected: [ + { + codePath: 'data/foo.1234.js', + mapPath: 'data/foo.1234.js.map', + }, + ], + }, + { + name: 'should expand multiple globs', + fileTokens: ['data/foo.1*.js', 'data/foo.mi?.js'], + expected: [ + { + codePath: 'data/foo.1234.js', + mapPath: 'data/foo.1234.js.map', + }, + { + codePath: 'data/foo.min.js', + mapPath: 'data/foo.min.js.map', + }, + ], + }, { name: 'should support single file glob when inline map', - args: ['data/foo.min.inline*.js'], + fileTokens: ['data/foo.min.inline*.js'], expected: [ { codePath: 'data/foo.min.inline-map.js', @@ -68,9 +92,9 @@ describe('getBundles - command line parsing', function() { }, ]; - tests.forEach(function({ name, args, expected }) { + tests.forEach(function({ name, fileTokens, expected }) { it(name, function() { - expect(getBundles(...args)).to.deep.equal(expected); + expect(getBundles(fileTokens)).to.deep.equal(expected); }); }); });