From c95e4bf08ab5968e259c6b687c2b5da4d5ab81be Mon Sep 17 00:00:00 2001 From: Daniel Koch Date: Wed, 20 Apr 2016 00:46:42 +0200 Subject: [PATCH] Add resolve property (#1) * Add a few more tests * Move things to the top * Add another helper * Use path.dirname instead of basename & split * Remove comments * Add first test for resolve * Add resolve feature If provided as an array a `resolve` key in the plugin's options is used to resolve existing files on the file system * Add tests for the resolve property * Update readme * Remove unused identity function * Use startsWith utility --- README.md | 17 ++++++++ src/index.js | 56 ++++++++++++++++++------- test/files/folder/hipster.jsx | 0 test/index.js | 79 ++++++++++++++++++++++++++++++++++- 4 files changed, 137 insertions(+), 15 deletions(-) create mode 100644 test/files/folder/hipster.jsx diff --git a/README.md b/README.md index ec72a95..06b74b8 100644 --- a/README.md +++ b/README.md @@ -25,5 +25,22 @@ rollup({ }); ``` +An optional `resolve` array with file extensions can be provided. +If present local aliases beginning with `./` will be resolved to existing files: + +```javascript +import { rollup } from 'rollup'; +import alias from 'rollup-plugin-alias'; + +rollup({ + entry: './src/index.js', + plugins: [alias({ + resolve: ['.jsx', '.js'] + foo: './bar', // Will check for ./bar.jsx and ./bar.js + })], +}); +``` +If not given local aliases will be resolved with a `.js` extension. + ## License MIT, see `LICENSE` for more information diff --git a/src/index.js b/src/index.js index 8fef1a5..e1dbbf6 100644 --- a/src/index.js +++ b/src/index.js @@ -1,30 +1,58 @@ import path from 'path'; +import fs from 'fs'; + +// Helper functions +const noop = () => null; +const startsWith = (needle, haystack) => ! haystack.indexOf(needle); +const exists = uri => { + try { + return fs.statSync(uri).isFile(); + } catch (e) { + return false; + } +}; export default function alias(options = {}) { + const hasResolve = Array.isArray(options.resolve); + const resolve = hasResolve ? options.resolve : ['.js']; + const aliasKeys = hasResolve ? + Object.keys(options).filter(k => k !== 'resolve') : Object.keys(options); + + // No aliases? + if (!aliasKeys.length) { + return { + resolveId: noop, + }; + } + return { resolveId(importee, importer) { - if (Object.keys(options).length === 0) { + // First match is supposed to be the correct one + const toReplace = aliasKeys.find(key => startsWith(key, importee)); + + if (!toReplace) { return null; } - const aliasKeys = Object.keys(options); - // TODO: We shouldn't have a case of double aliases. But may need to handle that better - const filteredAlias = aliasKeys.filter(value => importee.indexOf(value) === 0)[0]; + const entry = options[toReplace]; - if (!filteredAlias) { - return null; - } + const updatedId = importee.replace(toReplace, entry); - const entry = options[filteredAlias]; + if (startsWith('./', updatedId)) { + const directory = path.dirname(importer); - const updatedId = importee.replace(filteredAlias, entry); + // Resolve file names + const filePath = path.resolve(directory, updatedId); + const match = resolve.map(ext => `${filePath}${ext}`) + .find(exists); - if (updatedId.indexOf('./') === 0) { - const basename = path.basename(importer); - const directory = importer.split(basename)[0]; + if (match) { + return match; + } - // TODO: Is there a way not to have the extension being defined explicitly? - return path.resolve(directory, updatedId) + '.js'; + // To keep the previous behaviour we simply return the file path + // with extension + return filePath + '.js'; } return updatedId; diff --git a/test/files/folder/hipster.jsx b/test/files/folder/hipster.jsx new file mode 100644 index 0000000..e69de29 diff --git a/test/index.js b/test/index.js index 94577aa..a897967 100644 --- a/test/index.js +++ b/test/index.js @@ -1,8 +1,85 @@ import test from 'ava'; - +import path from 'path'; import { rollup } from 'rollup'; import alias from '../dist/rollup-plugin-alias'; +test(t => { + t.is(typeof alias, 'function'); +}); + +test(t => { + const result = alias(); + t.is(typeof result, 'object'); + t.is(typeof result.resolveId, 'function'); +}); + +test(t => { + const result = alias({}); + t.is(typeof result, 'object'); + t.is(typeof result.resolveId, 'function'); +}); + +// Simple aliasing +test(t => { + const result = alias({ + foo: 'bar', + pony: 'paradise', + }); + + const resolved = result.resolveId('foo', '/src/importer.js'); + const resolved2 = result.resolveId('pony', '/src/importer.js'); + + t.is(resolved, 'bar'); + t.is(resolved2, 'paradise'); +}); + +// Local aliasing +test(t => { + const result = alias({ + foo: './bar', + pony: './par/a/di/se', + }); + + const resolved = result.resolveId('foo', '/src/importer.js'); + const resolved2 = result.resolveId('pony', '/src/highly/nested/importer.js'); + + t.is(resolved, '/src/bar.js'); + t.is(resolved2, '/src/highly/nested/par/a/di/se.js'); +}); + +// Test for the resolve property +test(t => { + const result = alias({ + ember: './folder/hipster', + resolve: ['.js', '.jsx'], + }); + + const resolved = result.resolveId('ember', path.resolve(__dirname, './files/index.js')); + + t.is(resolved, path.resolve(__dirname, './files/folder/hipster.jsx')); +}); + +test(t => { + const result = alias({ + resolve: 'i/am/a/file', + }); + + const resolved = result.resolveId('resolve', '/src/import.js'); + + t.is(resolved, 'i/am/a/file'); +}); + +test(t => { + const result = alias({ + resolve: './i/am/a/local/file', + }); + + const resolved = result.resolveId('resolve', path.resolve(__dirname, './files/index.js')); + + t.is(resolved, path.resolve(__dirname, './files/i/am/a/local/file.js')); +}); + +// Tests in Rollup test(t => rollup({ entry: './files/index.js',