Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ indent_style = space
indent_size = 4

[*.{json,yml}]
indent_style = space
indent_size = 2

[.*]
indent_size = 2
12 changes: 6 additions & 6 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"extends": "airbnb-base",
"rules": {
"comma-dangle": 0,
"indent": [2, 4, {"SwitchCase": 1}],
"max-len": 0,
}
"extends": "airbnb-base",
"rules": {
"comma-dangle": 0,
"indent": [2, 4, {"SwitchCase": 1}],
"max-len": 0
}
}
52 changes: 32 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
# babel-plugin-module-alias
# babel-plugin-module-resolver
[![npm][npm-version-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Coverage Status][coverage-image]][coverage-url]

A [babel](http://babeljs.io) plugin to rewrite (map, alias, resolve) directories as different directories during the Babel process. It's particularly useful when you have files you don't want to use with relative paths (especially in big projects).
A [babel](http://babeljs.io) plugin to add a new resolver for your modules when compiling your code using Babel. The plugin allows you to add new "root" directories that contains your modules. It also allows your to setup custom alias which can also be directories or specific files, or even other npm modules.

## Description

Instead of using relative paths in your project, you'll be able to use an alias. Here an simple example:
The reason of this plugin is to simplify the require/import paths in your project. Therefore, instead of using complex relative paths like `../../../../utils/my-utils`, you would be able to write `utils/my-utils`. It will allow you to work faster since you won't need to calculate how many levels of directory you have to go up before accessing the file.

Here's a full example:
```js
// Instead of using this;
import MyUtilFn from '../../../../utils/MyUtilFn';
// Use that:
import MyUtilFn from 'utils/MyUtilFn';
```
With this plugin, you'll be able to map files or directories to the path you want.

_Note:_ It also work for `require()`.

Expand All @@ -24,34 +25,45 @@ _Note 2:_ You can use the `npm:` prefix in your plugin configuration to map a no
Install the plugin

```
$ npm install --save-dev babel babel-plugin-module-alias
$ npm install --save-dev babel-plugin-module-resolver
```

Specify the plugin in your `.babelrc` with the custom mapping.

Specify the plugin in your `.babelrc` with the custom root or alias. Here's an example:
```json
{
"plugins": [
["module-alias", [
{ "src": "./src/utils", "expose": "utils" },
{ "src": "./src/components", "expose": "awesome/components" },
{ "src": "npm:lodash", "expose": "underscore" }
]]
]
"transform-object-rest-spread",
["module-resolver", {
"root": ["./src"],
"alias": {
"test": "./test"
}
}]
]
}
```

If you're using [eslint-plugin-import][eslint-plugin-import], you should use [eslint-import-resolver-babel-module-alias][resolver-module-alias] to avoid having false errors.
## ESLint plugin

If you're using ESLint, you should use the [eslint-plugin-import][eslint-plugin-import], and this [eslint-import-resolver-babel-module-resolver][eslint-import-resolver-babel-module-resolver] in order to remove falsy unresolved modules.

## Editors autocompletion

- Atom: Uses [atom-autocomplete-modules][atom-autocomplete-modules] and enable the `babel-plugin-module-resolver` option.
- IntelliJ/WebStorm: You can add custom resources root directories, make sure it matches what you have in this plugin.

## License

MIT, see [LICENSE.md](/LICENSE.md) for details.


[ci-image]: https://circleci.com/gh/tleunen/babel-plugin-module-alias.svg?style=shield
[ci-url]: https://circleci.com/gh/tleunen/babel-plugin-module-alias
[coverage-image]: https://codecov.io/gh/tleunen/babel-plugin-module-alias/branch/master/graph/badge.svg
[coverage-url]: https://codecov.io/gh/tleunen/babel-plugin-module-alias
[npm-version-image]: https://img.shields.io/npm/v/babel-plugin-module-alias.svg
[npm-url]: https://www.npmjs.com/package/babel-plugin-module-alias
[resolver-module-alias]: https://github.com/tleunen/eslint-import-resolver-babel-module-alias
[ci-image]: https://circleci.com/gh/tleunen/babel-plugin-module-resolver.svg?style=shield
[ci-url]: https://circleci.com/gh/tleunen/babel-plugin-module-resolver
[coverage-image]: https://codecov.io/gh/tleunen/babel-plugin-module-resolver/branch/master/graph/badge.svg
[coverage-url]: https://codecov.io/gh/tleunen/babel-plugin-module-resolver
[npm-version-image]: https://img.shields.io/npm/v/babel-plugin-module-resolver.svg
[npm-url]: https://www.npmjs.com/package/babel-plugin-module-resolver
[eslint-import-resolver-babel-module-resolver]: https://github.com/tleunen/eslint-import-resolver-babel-module-resolver
[eslint-plugin-import]: https://github.com/benmosher/eslint-plugin-import
[atom-autocomplete-modules]: https://github.com/nkt/atom-autocomplete-modules
2 changes: 1 addition & 1 deletion codecov.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
comment:
layout: "header, diff, tree"
layout: "header, tree"
18 changes: 9 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "babel-plugin-module-alias",
"name": "babel-plugin-module-resolver",
"version": "1.6.0",
"main": "lib/index.js",
"description": "Babel plugin to rewrite the path in require() and ES6 import",
"repository": {
"type": "git",
"url": "https://github.com/tleunen/babel-plugin-module-alias.git"
"url": "https://github.com/tleunen/babel-plugin-module-resolver.git"
},
"author": {
"name": "Tommy Leunen",
Expand All @@ -17,6 +17,7 @@
"babel",
"babel-plugin",
"module",
"resolver",
"alias",
"rewrite",
"resolve",
Expand All @@ -25,19 +26,18 @@
"require",
"import"
],
"dependencies": {},
"devDependencies": {
"babel-cli": "^6.10.1",
"babel-core": "^6.10.4",
"babel-plugin-istanbul": "^1.1.0",
"babel-plugin-istanbul": "^2.0.0",
"babel-preset-es2015": "^6.6.0",
"babel-register": "^6.8.0",
"cross-env": "^2.0.0",
"eslint": "^3.0.1",
"eslint-config-airbnb-base": "^5.0.0",
"eslint-plugin-import": "^1.10.2",
"mocha": "^3.0.0",
"nyc": "^7.0.0",
"eslint": "^3.3.0",
"eslint-config-airbnb-base": "^5.0.2",
"eslint-plugin-import": "^1.13.0",
"mocha": "^3.0.2",
"nyc": "^8.1.0",
"standard-version": "^2.4.0"
},
"scripts": {
Expand Down
88 changes: 36 additions & 52 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,68 +1,54 @@
const path = require('path');

function createFilesMap(state) {
const result = {};
const opts = Array.isArray(state.opts)
? state.opts
: [state.opts];

opts.forEach(moduleMapData => {
result[moduleMapData.expose] = moduleMapData.src;
});

return result;
}

function resolve(filename) {
if (path.isAbsolute(filename)) return filename;
return path.resolve(process.cwd(), filename);
}

function toPosixPath(modulePath) {
return modulePath.replace(/\\/g, '/');
import path from 'path';
import mapToRelative from './mapToRelative';

function createAliasFileMap(pluginOpts) {
const alias = pluginOpts.alias || {};
return Object.keys(alias).reduce((memo, expose) => (
Object.assign(memo, {
[expose]: alias[expose]
})
), {});
}

export function mapToRelative(currentFile, module) {
let from = path.dirname(currentFile);
let to = path.normalize(module);

from = resolve(from);
to = resolve(to);

let moduleMapped = path.relative(from, to);

moduleMapped = toPosixPath(moduleMapped);

// Support npm modules instead of directories
if (moduleMapped.indexOf('npm:') !== -1) {
const [, npmModuleName] = moduleMapped.split('npm:');
return npmModuleName;
export function mapModule(source, file, pluginOpts) {
// Do not map source starting with a dot
if (source[0] === '.') {
return null;
}

if (moduleMapped[0] !== '.') moduleMapped = `./${moduleMapped}`;

return moduleMapped;
}
// Search the file under the custom root directories
const rootDirs = pluginOpts.root || [];
for (let i = 0; i < rootDirs.length; i++) {
try {
// check if the file exists (will throw if not)
const p = path.resolve(rootDirs[i], source);
require.resolve(p);
return mapToRelative(file, p);
} catch (e) {
// empty...
}
}

export function mapModule(source, file, filesMap) {
// The source file wasn't found in any of the root directories. Lets try the alias
const aliasMapping = createAliasFileMap(pluginOpts);
const moduleSplit = source.split('/');

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

if (!moduleSplit.length) {
// no mapping available
// no alias mapping found
if (!aliasPath) {
return null;
}

const newPath = source.replace(moduleSplit.join('/'), src);
const newPath = source.replace(moduleSplit.join('/'), aliasPath);
return mapToRelative(file, newPath);
}

Expand All @@ -81,8 +67,7 @@ export default ({ types: t }) => {

const moduleArg = nodePath.node.arguments[0];
if (moduleArg && moduleArg.type === 'StringLiteral') {
const filesMap = createFilesMap(state);
const modulePath = mapModule(moduleArg.value, state.file.opts.filename, filesMap);
const modulePath = mapModule(moduleArg.value, state.file.opts.filename, state.opts);
if (modulePath) {
nodePath.replaceWith(t.callExpression(
nodePath.node.callee, [t.stringLiteral(modulePath)]
Expand All @@ -94,8 +79,7 @@ export default ({ types: t }) => {
function transformImportCall(nodePath, state) {
const moduleArg = nodePath.node.source;
if (moduleArg && moduleArg.type === 'StringLiteral') {
const filesMap = createFilesMap(state);
const modulePath = mapModule(moduleArg.value, state.file.opts.filename, filesMap);
const modulePath = mapModule(moduleArg.value, state.file.opts.filename, state.opts);
if (modulePath) {
nodePath.replaceWith(t.importDeclaration(
nodePath.node.specifiers,
Expand Down
32 changes: 32 additions & 0 deletions src/mapToRelative.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import path from 'path';

function resolve(filename) {
if (path.isAbsolute(filename)) return filename;
return path.resolve(process.cwd(), filename);
}

function toPosixPath(modulePath) {
return modulePath.replace(/\\/g, '/');
}

export default function mapToRelative(currentFile, module) {
let from = path.dirname(currentFile);
let to = path.normalize(module);

from = resolve(from);
to = resolve(to);

let moduleMapped = path.relative(from, to);

moduleMapped = toPosixPath(moduleMapped);

// Support npm modules instead of directories
if (moduleMapped.indexOf('npm:') !== -1) {
const [, npmModuleName] = moduleMapped.split('npm:');
return npmModuleName;
}

if (moduleMapped[0] !== '.') moduleMapped = `./${moduleMapped}`;

return moduleMapped;
}
Empty file added test/examples/components/c1.js
Empty file.
Empty file added test/examples/components/c2.js
Empty file.
Empty file.
Empty file added test/examples/example-file.js
Empty file.
Loading