Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
501b839
Join aliases and regular expressions (no change in behavior)
fatfisz Apr 9, 2017
fa481cd
Always localize aliased paths (also reg exp)
fatfisz Apr 9, 2017
3e15eec
Move the aliasedSourceFile processing outside the loop
fatfisz Apr 9, 2017
b42ceb2
Print a deprecation warning when npm: is in the config
fatfisz Apr 9, 2017
c55a2d0
Try to resolve aliased paths using the root and cwd
fatfisz Apr 9, 2017
fda055b
Add a test for root and alias resolving order
fatfisz Apr 9, 2017
024dcb1
Remove support for npm: completely
fatfisz Apr 9, 2017
81d528d
Do only one pass over the aliasKeys array
fatfisz Apr 9, 2017
da1fcd9
Fix a typo
fatfisz Apr 10, 2017
1b4f87f
Don't resolve aliased paths again
fatfisz Apr 10, 2017
c59bcee
Restore the test for the double alias application
fatfisz Apr 10, 2017
040bb1c
Remove a useless test (alias is not resolved if it's a package name)
fatfisz Apr 10, 2017
7c71d3e
Make most alias paths into relative ones
fatfisz Apr 10, 2017
ce36607
Remove obsolete tests
fatfisz Apr 10, 2017
5b1b900
Warn if the package cannot be resolved after aliasing
fatfisz Apr 10, 2017
3caaaa1
Fix paths in the tests.
fatfisz Apr 10, 2017
c0baaa0
Use opts.extensions for resolving the aliased module path
fatfisz Apr 13, 2017
66bc9c6
Add a missing test for the production environment
fatfisz Apr 13, 2017
dc01d6d
Al aliases should be tried in the enumeration order
fatfisz Apr 13, 2017
8e55566
Merge branch 'beta' into resolve-alias-using-root
fatfisz Apr 13, 2017
647ce41
Add a useful test
fatfisz Apr 13, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@
"jest": {
"testRegex": "/test/.*\\.test\\.js$",
"collectCoverageFrom": [
"src/**/*.js"
"src/**/*.js",
"!src/log.js"
]
},
"greenkeeper": {
Expand Down
57 changes: 27 additions & 30 deletions src/getRealPath.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import path from 'path';

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


const nodeExtensions = ['.js', '.json'];

function findPathInRoots(sourcePath, { extensions, root }) {
// Search the source path inside every custom root directory
let resolvedSourceFile;
Expand Down Expand Up @@ -43,40 +46,21 @@ 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) {
try {
resolve.sync(modulePath, {
basedir: currentFile,
extensions: nodeExtensions,
Copy link
Copy Markdown
Owner

@tleunen tleunen Apr 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed that, but actually it should be the custom extensions the user sets, or the babel extension.

so extensions from opts.

And we should reuse this function in findPathInRoots to remove the duplicate.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this one - the packages are 3rd party and so they will probably have standard extensions.

OTOH it shouldn't hurt much to include more files in the lookup, as long as they are package-ish (what should be ensured by require.resolve). In the worst case there will be false positives, which would result in some warnings being silenced, but it doesn't sound very bad.

I'll go with your suggested change.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm.. Maybe I missed a detail, but it was used in the alias config to test the alias was actually pointing to an existing file (or node_modules). By 3rd party, you mean a node_module package, right?

If we really want to be safe, we could use the user/babel extensions for local files/modules and then the node extensions for the ones under node_modules (the ones who don't start with ./). But would it be really useful? Doesn't seem like it's really worth it to me. Again, we'll iterate if really needed, otherwise I'm ok with potential false positives. Anyway, this is only a helper for the user. We never checked the alias was correct in any previous versions so it's already a bit better now :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, a node_modules package. And yes, let's just see if anyone complains at all :)

});
} catch (e) {
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 +71,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);
}

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);
}
53 changes: 33 additions & 20 deletions src/normalizeOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,29 +51,42 @@ 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);
const nonRegExpAliases = [];
const regExpAliases = [];

aliasKeys.forEach((key) => {
if (isRegExp(key)) {
regExpAliases.push(
getAliasPair(key, alias[key]),
);
} else {
nonRegExpAliases.push(
getAliasPair(`^${key}((?:/|).*)`, `${alias[key]}\\1`),
);
}
});

opts.alias = [...nonRegExpAliases, ...regExpAliases];
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of this?

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to preserve the order: standard aliases before regexps. At this point I think it could go either way, as the order should be taken from the object.

Note: according to the spec, the order of enumerating the object keys is not guaranteed to be the same as in the literal, so in the future it may be needed to allow an array-type declaration. We're currently relying on V8.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, one or the other, we'll have an issue if a user expects the order to be kept. With an object, it's not guaranteed as you say. We'll figure out a way later if really needed. For now, it doesn't seem like users need it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll go with the single array then.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(btw. map is even better than forEach here, will use that instead)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed.

} else {
opts.alias = {};
opts.alias = [];
}
}

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