Skip to content

Commit

Permalink
Feat: warn when the package from resolved alias is not available (#160)
Browse files Browse the repository at this point in the history
Breaking change: The "npm:" prefix has been removed.
  • Loading branch information
fatfisz authored and Tommy Leunen committed Apr 23, 2017
1 parent 52600af commit c937f79
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 122 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@
"jest": {
"testRegex": "/test/.*\\.test\\.js$",
"collectCoverageFrom": [
"src/**/*.js"
"src/**/*.js",
"!src/log.js"
]
},
"greenkeeper": {
Expand Down
66 changes: 24 additions & 42 deletions src/getRealPath.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
import path from 'path';

import resolve from 'resolve';
import { warn } from './log';
import mapToRelative from './mapToRelative';
import { toLocalPath, toPosixPath, replaceExtension } from './utils';
import { nodeResolvePath, replaceExtension, toLocalPath, toPosixPath } from './utils';


function findPathInRoots(sourcePath, { extensions, root }) {
// Search the source path inside every custom root directory
let resolvedSourceFile;

root.some((basedir) => {
try {
// Check if the file exists (will throw if not)
resolvedSourceFile = resolve.sync(`./${sourcePath}`, {
basedir,
extensions,
});
return true;
} catch (e) {
return false;
}
resolvedSourceFile = nodeResolvePath(`./${sourcePath}`, basedir, extensions);
return resolvedSourceFile !== null;
});

return resolvedSourceFile;
Expand All @@ -43,40 +35,17 @@ function getRealPathFromRootConfig(sourcePath, currentFile, opts) {
)));
}

function getRealPathFromAliasConfig(sourcePath, currentFile, { alias, cwd }) {
const moduleSplit = sourcePath.split('/');
let aliasPath;

while (moduleSplit.length) {
const m = moduleSplit.join('/');
if ({}.hasOwnProperty.call(alias, m)) {
aliasPath = alias[m];
break;
}
moduleSplit.pop();
}

// no alias mapping found
if (!aliasPath) {
return null;
}

// remove legacy "npm:" prefix for npm packages
aliasPath = aliasPath.replace(/^(npm:)/, '');
const newPath = sourcePath.replace(moduleSplit.join('/'), aliasPath);

// alias to npm module don't need relative mapping
if (aliasPath[0] !== '.') {
return newPath;
function checkIfPackageExists(modulePath, currentFile, extensions) {
const resolvedPath = nodeResolvePath(modulePath, currentFile, extensions);
if (resolvedPath === null) {
warn(`Could not resolve "${modulePath}" in file ${currentFile}.`);
}

return toLocalPath(toPosixPath(mapToRelative(cwd, currentFile, newPath)));
}

function getRealPathFromRegExpConfig(sourcePath, currentFile, { regExps }) {
function getRealPathFromAliasConfig(sourcePath, currentFile, opts) {
let aliasedSourceFile;

regExps.find(([regExp, substitute]) => {
opts.alias.find(([regExp, substitute]) => {
const execResult = regExp.exec(sourcePath);

if (execResult === null) {
Expand All @@ -87,13 +56,26 @@ function getRealPathFromRegExpConfig(sourcePath, currentFile, { regExps }) {
return true;
});

if (!aliasedSourceFile) {
return null;
}

if (aliasedSourceFile[0] === '.') {
return toLocalPath(toPosixPath(
mapToRelative(opts.cwd, currentFile, aliasedSourceFile)),
);
}

if (process.env.NODE_ENV !== 'production') {
checkIfPackageExists(aliasedSourceFile, currentFile, opts.extensions);
}

return aliasedSourceFile;
}

const resolvers = [
getRealPathFromRootConfig,
getRealPathFromAliasConfig,
getRealPathFromRegExpConfig,
];

export default function getRealPath(sourcePath, { file, opts }) {
Expand Down
7 changes: 7 additions & 0 deletions src/log.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// This module exists only for abstracting logging away and making testing easier

// eslint-disable-next-line import/prefer-default-export
export function warn(...args) {
// eslint-disable-next-line no-console
console.warn(...args);
}
43 changes: 23 additions & 20 deletions src/normalizeOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,29 +60,32 @@ function normalizeRoot(opts) {
}
}

function normalizeAlias(opts) {
opts.regExps = [];

if (opts.alias) {
Object.keys(opts.alias)
.filter(isRegExp)
.forEach((key) => {
const parts = opts.alias[key].split('\\\\');

function substitute(execResult) {
return parts
.map(part =>
part.replace(/\\\d+/g, number => execResult[number.slice(1)] || ''),
)
.join('\\');
}
function getAliasPair(key, value) {
const parts = value.split('\\\\');

function substitute(execResult) {
return parts
.map(part =>
part.replace(/\\\d+/g, number => execResult[number.slice(1)] || ''),
)
.join('\\');
}

opts.regExps.push([new RegExp(key), substitute]);
return [new RegExp(key), substitute];
}

delete opts.alias[key];
});
function normalizeAlias(opts) {
if (opts.alias) {
const { alias } = opts;
const aliasKeys = Object.keys(alias);

opts.alias = aliasKeys.map(key => (
isRegExp(key) ?
getAliasPair(key, alias[key]) :
getAliasPair(`^${key}((?:/|).*)`, `${alias[key]}\\1`)
));
} else {
opts.alias = {};
opts.alias = [];
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import path from 'path';

import resolve from 'resolve';
import getRealPath from './getRealPath';


export function nodeResolvePath(modulePath, basedir, extensions) {
try {
return resolve.sync(modulePath, { basedir, extensions });
} catch (e) {
return null;
}
}

export function toPosixPath(modulePath) {
return modulePath.replace(/\\/g, '/');
}
Expand Down
10 changes: 10 additions & 0 deletions test/import.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ describe('import and export statement', () => {
root: './test/testproject/src',
alias: {
test: './test/testproject/test',
'babel-core': 'babel-core/lib',
},
}],
],
Expand Down Expand Up @@ -121,6 +122,15 @@ describe('import and export statement', () => {
);
});

describe('should only apply the alias once', () => {
// If this test breaks, consider selecting another package used by the plugin
testImports(
'babel-core/store',
'babel-core/lib/store',
transformerOpts,
);
});

describe('should ignore the call if a non-import statement is used', () => {
const code = stripIndent`
function test() {
Expand Down
Loading

0 comments on commit c937f79

Please sign in to comment.