Skip to content

Commit

Permalink
feat: Add regular expression support (#132)
Browse files Browse the repository at this point in the history
Closes #88.
Closes #127.
  • Loading branch information
fatfisz authored and tleunen committed Mar 15, 2017
1 parent 4325ad5 commit 6d87b25
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 0 deletions.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,28 @@ Specify the plugin in your `.babelrc` with the custom root or alias. Here's an e
- `cwd`: By default, the working directory is the one used for the resolver, but you can override it for your project.
- The custom value `babelrc` will make the plugin look for the closest babelrc configuration based on the file to parse.

### Regular expression alias

It is possible to specify an alias using a regular expression. To do that, either start an alias with `'^'` or end it with `'$'`:

```json
{
"plugins": [
["module-resolver", {
"alias": {
"^@namespace/foo-(.+)": "packages/\\1"
}
}]
]
}
```

Using the config from this example `'@namespace/foo-bar'` will become `'packages/bar'`.

You can reference the n-th matched group with `'\\n'` (`'\\0'` refers to the whole matched path).

To use the backslash character (`\`) just escape it like so: `'\\\\'` (double escape is needed because of JSON already using `\` for escaping).

### Updating from babel-plugin-module-alias

babel-plugin-module-resolver is a new version of the old babel-plugin-module-alias. Therefore, you also need to make a few modifications to your plugin configuration to make it work with this new plugin.
Expand Down
25 changes: 25 additions & 0 deletions src/getRealPath.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,23 @@ function getRealPathFromAliasConfig(sourcePath, absCurrentFile, alias, cwd) {
return toLocalPath(toPosixPath(mapToRelative(cwd, absCurrentFile, newPath)));
}

function getRealPathFromRegExpConfig(sourcePath, regExps) {
let aliasedSourceFile;

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

if (execResult === null) {
return false;
}

aliasedSourceFile = substitute(execResult);
return true;
});

return aliasedSourceFile;
}

export default function getRealPath(sourcePath, currentFile, opts) {
if (sourcePath[0] === '.') {
return sourcePath;
Expand All @@ -81,6 +98,7 @@ export default function getRealPath(sourcePath, currentFile, opts) {

const { cwd, extensions, pluginOpts } = opts;
const rootDirs = pluginOpts.root || [];
const regExps = pluginOpts.regExps;
const alias = pluginOpts.alias || {};

const sourceFileFromRoot = getRealPathFromRootConfig(
Expand All @@ -97,5 +115,12 @@ export default function getRealPath(sourcePath, currentFile, opts) {
return sourceFileFromAlias;
}

const sourceFileFromRegExp = getRealPathFromRegExpConfig(
sourcePath, regExps,
);
if (sourceFileFromRegExp) {
return sourceFileFromRegExp;
}

return sourcePath;
}
28 changes: 28 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export function mapModule(sourcePath, currentFile, pluginOpts, cwd) {
});
}

function isRegExp(string) {
return string.startsWith('^') || string.endsWith('$');
}

export function manipulatePluginOptions(pluginOpts) {
if (pluginOpts.root) {
// eslint-disable-next-line no-param-reassign
Expand All @@ -32,6 +36,30 @@ export function manipulatePluginOptions(pluginOpts) {
}, []);
}

// eslint-disable-next-line no-param-reassign
pluginOpts.regExps = [];

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

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

pluginOpts.regExps.push([new RegExp(key), substitute]);

// eslint-disable-next-line no-param-reassign
delete pluginOpts.alias[key];
});
}

return pluginOpts;
}

Expand Down
68 changes: 68 additions & 0 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,13 @@ describe('module-resolver', () => {
'awesome/components': './test/testproject/src/components',
abstract: 'npm:concrete',
underscore: 'lodash',
'^@namespace/foo-(.+)': 'packages/\\1',
'styles/.+\\.(css|less|scss)$': 'style-proxy.\\1',
'^single-backslash': 'pas\\\\sed',
'^non-existing-match': 'pas\\42sed',
'^regexp-priority': 'miss',
'regexp-priority$': 'miss',
'regexp-priority': 'hit',
},
}],
],
Expand Down Expand Up @@ -287,6 +294,67 @@ describe('module-resolver', () => {
aliasTransformerOpts,
);
});

describe('with a regular expression', () => {
describe('should support replacing parts of a path', () => {
testRequireImport(
'@namespace/foo-bar',
'packages/bar',
aliasTransformerOpts,
);
});

describe('should support replacing parts of a complex path', () => {
testRequireImport(
'@namespace/foo-bar/component.js',
'packages/bar/component.js',
aliasTransformerOpts,
);
});

describe('should support complex regular expressions', () => {
['css', 'less', 'scss'].forEach((extension) => {
testRequireImport(
`styles/style.${extension}`,
`style-proxy.${extension}`,
aliasTransformerOpts,
);
});
});

describe('should ignore unmatched paths', () => {
testRequireImport(
'styles/style.js',
'styles/style.js',
aliasTransformerOpts,
);
});

describe('should transform double backslash into a single one', () => {
testRequireImport(
'single-backslash',
// This is a string literal, so in the code it will actually be "pas\\sed"
'pas\\\\sed',
aliasTransformerOpts,
);
});

describe('should replece missing matches with an empty string', () => {
testRequireImport(
'non-existing-match',
'passed',
aliasTransformerOpts,
);
});

describe('should have higher priority than a simple alias', () => {
testRequireImport(
'regexp-priority',
'hit',
aliasTransformerOpts,
);
});
});
});

describe('with custom cwd', () => {
Expand Down

0 comments on commit 6d87b25

Please sign in to comment.