diff --git a/src/index.js b/src/index.js index d789813..596fa59 100644 --- a/src/index.js +++ b/src/index.js @@ -1,12 +1,7 @@ -import { posix as path } from 'path'; -import { platform } from 'os'; +import path from 'path'; import fs from 'fs'; - import slash from 'slash'; -const VOLUME = /^([A-Z]:)/; -const IS_WINDOWS = platform() === 'win32'; - // Helper functions const noop = () => null; const matches = (key, importee) => { @@ -21,7 +16,8 @@ const matches = (key, importee) => { return importeeStartsWithKey && importeeHasSlashAfterKey; }; const endsWith = (needle, haystack) => haystack.slice(-needle.length) === needle; -const isFilePath = id => /^\.?\//.test(id); +const isAbsolutePath = id => /^(?:\/|(?:[A-Za-z]:)?[\\\/])/.test(id); +const isRelativePath = id => /^\.?\.[\\\/]/.test(id); const exists = uri => { try { return fs.statSync(uri).isFile(); @@ -29,10 +25,9 @@ const exists = uri => { return false; } }; - const normalizeId = id => { - if (IS_WINDOWS && typeof id === 'string') { - return slash(id.replace(VOLUME, '')); + if (typeof id === 'string') { + return slash(id); } return id; @@ -63,29 +58,35 @@ export default function alias(options = {}) { return null; } - const entry = options[toReplace]; + const entry = normalizeId(options[toReplace]); const updatedId = importeeId.replace(toReplace, entry); - if (isFilePath(updatedId)) { - const directory = path.dirname(importerId); + if (isRelativePath(updatedId) || isAbsolutePath(updatedId)) { + let filePath; + if (isRelativePath(updatedId) && importer === undefined) { + // Cannot handle this, so return null + return null; + } else if (isRelativePath(updatedId) && importer !== undefined) { + // Resolve file names + filePath = path.resolve(path.dirname(importerId), updatedId); + } else { + // Absolute path doesn't need resolve + filePath = updatedId; + } - // Resolve file names - const filePath = path.resolve(directory, updatedId); const match = resolve.map(ext => `${filePath}${ext}`) .find(exists); if (match) { - return match; - } - - // To keep the previous behaviour we simply return the file path - // with extension - if (endsWith('.js', filePath)) { - return filePath; + filePath = match; + } else if (!endsWith('.js', filePath)) { + // To keep the previous behaviour we simply return the file path + // with extension + filePath = filePath + '.js'; } - return filePath + '.js'; + return normalizeId(filePath); } return updatedId; diff --git a/test/index.js b/test/index.js index 01cecb9..94b0dc5 100644 --- a/test/index.js +++ b/test/index.js @@ -1,10 +1,10 @@ import test from 'ava'; -import { posix as path } from 'path'; +import path from 'path'; import { rollup } from 'rollup'; import alias from '../dist/rollup-plugin-alias'; import slash from 'slash'; -const DIRNAME = slash(__dirname.replace(/^([A-Z]:)/, '')); +const normalizeId = id => slash(id); test(t => { t.is(typeof alias, 'function'); @@ -29,9 +29,9 @@ test('Simple aliasing', t => { './local': 'global', }); - const resolved = result.resolveId('foo', '/src/importer.js'); - const resolved2 = result.resolveId('pony', '/src/importer.js'); - const resolved3 = result.resolveId('./local', '/src/importer.js'); + const resolved = result.resolveId('foo', path.resolve('/src/importer.js')); + const resolved2 = result.resolveId('pony', path.resolve('/src/importer.js')); + const resolved3 = result.resolveId('./local', path.resolve('/src/importer.js')); t.is(resolved, 'bar'); t.is(resolved2, 'paradise'); @@ -44,47 +44,64 @@ test('Will not confuse modules with similar names', t => { './foo': 'bar', }); - const resolved = result.resolveId('foo2', '/src/importer.js'); - const resolved2 = result.resolveId('./fooze/bar', '/src/importer.js'); - const resolved3 = result.resolveId('./someFile.foo', '/src/importer.js'); + const resolved = result.resolveId('foo2', path.resolve('/src/importer.js')); + const resolved2 = result.resolveId('./fooze/bar', path.resolve('/src/importer.js')); + const resolved3 = result.resolveId('./someFile.foo', path.resolve('/src/importer.js')); t.is(resolved, null); t.is(resolved2, null); t.is(resolved3, null); }); -test('Local aliasing', t => { +test('Local aliasing with POSIX path', t => { const result = alias({ foo: './bar', pony: './par/a/di/se', }); - const resolved = result.resolveId('foo', '/src/importer.js'); - const resolved2 = result.resolveId('foo/baz', '/src/importer.js'); - const resolved3 = result.resolveId('foo/baz.js', '/src/importer.js'); - const resolved4 = result.resolveId('pony', '/src/highly/nested/importer.js'); + const resolved = result.resolveId('foo', path.resolve('/src/importer.js')); + const resolved2 = result.resolveId('foo/baz', path.resolve('/src/importer.js')); + const resolved3 = result.resolveId('foo/baz.js', path.resolve('/src/importer.js')); + const resolved4 = result.resolveId('pony', path.resolve('/src/highly/nested/importer.js')); - t.is(resolved, '/src/bar.js'); - t.is(resolved2, '/src/bar/baz.js'); - t.is(resolved3, '/src/bar/baz.js'); - t.is(resolved4, '/src/highly/nested/par/a/di/se.js'); + t.is(resolved, normalizeId(path.resolve('/src/bar.js'))); + t.is(resolved2, normalizeId(path.resolve('/src/bar/baz.js'))); + t.is(resolved3, normalizeId(path.resolve('/src/bar/baz.js'))); + t.is(resolved4, normalizeId(path.resolve('/src/highly/nested/par/a/di/se.js'))); +}); + +test('Local aliasing with Windows path', t => { + const result = alias({ + foo: '.\\bar', + pony: '.\\par\\a\\di\\se', + }); + + const resolved = result.resolveId('foo', path.resolve('/src/importer.js')); + const resolved2 = result.resolveId('foo/baz', path.resolve('/src/importer.js')); + const resolved3 = result.resolveId('foo/baz.js', path.resolve('/src/importer.js')); + const resolved4 = result.resolveId('pony', path.resolve('/src/highly/nested/importer.js')); + + t.is(resolved, normalizeId(path.resolve('/src/bar.js'))); + t.is(resolved2, normalizeId(path.resolve('/src/bar/baz.js'))); + t.is(resolved3, normalizeId(path.resolve('/src/bar/baz.js'))); + t.is(resolved4, normalizeId(path.resolve('/src/highly/nested/par/a/di/se.js'))); }); test('Absolute local aliasing', t => { const result = alias({ - foo: '/bar', - pony: '/par/a/di/se.js', + foo: path.resolve('/bar'), + pony: path.resolve('/par/a/di/se.js'), }); - const resolved = result.resolveId('foo', '/src/importer.js'); - const resolved2 = result.resolveId('foo/baz', '/src/importer.js'); - const resolved3 = result.resolveId('foo/baz.js', '/src/importer.js'); - const resolved4 = result.resolveId('pony', '/src/highly/nested/importer.js'); + const resolved = result.resolveId('foo', path.resolve('/src/importer.js')); + const resolved2 = result.resolveId('foo/baz', path.resolve('/src/importer.js')); + const resolved3 = result.resolveId('foo/baz.js', path.resolve('/src/importer.js')); + const resolved4 = result.resolveId('pony', path.resolve('/src/highly/nested/importer.js')); - t.is(resolved, '/bar.js'); - t.is(resolved2, '/bar/baz.js'); - t.is(resolved3, '/bar/baz.js'); - t.is(resolved4, '/par/a/di/se.js'); + t.is(resolved, normalizeId(path.resolve('/bar.js'))); + t.is(resolved2, normalizeId(path.resolve('/bar/baz.js'))); + t.is(resolved3, normalizeId(path.resolve('/bar/baz.js'))); + t.is(resolved4, normalizeId(path.resolve('/par/a/di/se.js'))); }); test('Test for the resolve property', t => { @@ -93,9 +110,9 @@ test('Test for the resolve property', t => { resolve: ['.js', '.jsx'], }); - const resolved = result.resolveId('ember', path.resolve(DIRNAME, './files/index.js')); + const resolved = result.resolveId('ember', path.resolve(__dirname, './files/index.js')); - t.is(resolved, path.resolve(DIRNAME, './files/folder/hipster.jsx')); + t.is(resolved, normalizeId(path.resolve(__dirname, './files/folder/hipster.jsx'))); }); test(t => { @@ -103,7 +120,7 @@ test(t => { resolve: 'i/am/a/file', }); - const resolved = result.resolveId('resolve', '/src/import.js'); + const resolved = result.resolveId('resolve', path.resolve('/src/import.js')); t.is(resolved, 'i/am/a/file'); }); @@ -113,9 +130,9 @@ test(t => { resolve: './i/am/a/local/file', }); - const resolved = result.resolveId('resolve', path.resolve(DIRNAME, './files/index.js')); + const resolved = result.resolveId('resolve', path.resolve(__dirname, './files/index.js')); - t.is(resolved, path.resolve(DIRNAME, './files/i/am/a/local/file.js')); + t.is(resolved, normalizeId(path.resolve(__dirname, './files/i/am/a/local/file.js'))); }); // Tests in Rollup @@ -129,11 +146,37 @@ test(t => './numberFolder': './folder', })], }).then(stats => { - t.is(stats.modules[0].id.endsWith('/files/nonAliased.js'), true); - t.is(stats.modules[1].id.endsWith('/files/aliasMe.js'), true); - t.is(stats.modules[2].id.endsWith('/files/localAliasMe.js'), true); - t.is(stats.modules[3].id.endsWith('/files/folder/anotherNumber.js'), true); - t.is(stats.modules[4].id.endsWith('/files/index.js'), true); + t.is(stats.modules[0].id, normalizeId(path.resolve('./files/nonAliased.js'))); + t.is(stats.modules[1].id, normalizeId(path.resolve('./files/aliasMe.js'))); + t.is(stats.modules[2].id, normalizeId(path.resolve('./files/localAliasMe.js'))); + t.is(stats.modules[3].id, normalizeId(path.resolve('./files/folder/anotherNumber.js'))); + t.is(stats.modules[4].id, normalizeId(path.resolve('./files/index.js'))); t.is(stats.modules.length, 5); }) ); + +test('Relative local aliasing in rollup entry', t => + rollup({ + entry: 'src/aliasMe.js', + plugins: [alias({ + src: './files', + })], + }).then(() => { + t.fail(); + }).catch(() => { + t.pass(); + }) +); + +test('Absolute local aliasing in rollup entry', t => + rollup({ + entry: 'src/aliasMe.js', + plugins: [alias({ + src: path.resolve('./files'), + })], + }).then(() => { + t.pass(); + }).catch(() => { + t.fail(); + }) +);