Skip to content

Commit

Permalink
feat: Allow using a function to define the result of an alias (#245)
Browse files Browse the repository at this point in the history
  • Loading branch information
fatfisz authored and tleunen committed Dec 13, 2017
1 parent 0fa7b3a commit 9299d9a
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 18 deletions.
30 changes: 28 additions & 2 deletions DOCS.md
Expand Up @@ -66,6 +66,32 @@ You can reference the n-th matched group with `'\\n'` (`'\\0'` refers to the who

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

### Passing a substitute function

If you need even more power over the aliased path, you can pass a function in the alias configuration:

```js
module.exports = {
plugins: [
["module-resolver", {
alias: {
"foo": ([, name]) => `bar${name}`,
"^@namespace/foo-(.+)": ([, name]) => `packages/${name}`
}
}]
]
}
```

Using the config from this example:
* `'foo'` will become `'bar'` (`name` is empty)
* `'foo/baz'` will become `'bar/baz'` (`name` includes the slash in this case)
* `'@namespace/foo-bar'` will become `'packages/bar'`

The only argument is the result of calling `RegExp.prototype.exec` on the matched path. It's an array with the matched string and all matched groups.

Because the function is only called when there is a match, the argument can never be `null`.

## extensions

An array of extensions used in the resolver.
Expand Down Expand Up @@ -95,7 +121,7 @@ Array of functions and methods that will have their first argument transformed.
"plugins": [
["module-resolver", {
"transformFunctions": [
"require",
"require",
"require.resolve",
"System.import",
"jest.genMockFromModule",
Expand Down Expand Up @@ -224,4 +250,4 @@ const realPath = resolvePath(sourcePath, currentFile, opts);

For each path in the file you can use `resolvePath` to get the same path that module-resolver will output.

`currentFile` can be either a relative path (will be resolved with respect to the CWD, not `opts.cwd`), or an absolute path.
`currentFile` can be either a relative path (will be resolved with respect to the CWD, not `opts.cwd`), or an absolute path.
41 changes: 25 additions & 16 deletions src/normalizeOptions.js
Expand Up @@ -78,18 +78,27 @@ function normalizeRoot(optsRoot, cwd) {
}, []);
}

function getAliasPair(key, value) {
const parts = value.split('\\\\');
function getAliasTarget(key, isKeyRegExp) {
const regExpPattern = isKeyRegExp ? key : `^${key}(/.*|)$`;
return new RegExp(regExpPattern);
}

function getAliasSubstitute(value, isKeyRegExp) {
if (typeof value === 'function') {
return value;
}

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

return [new RegExp(key), substitute];
const parts = value.split('\\\\');

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

function normalizeAlias(optsAlias) {
Expand All @@ -99,18 +108,18 @@ function normalizeAlias(optsAlias) {

const aliasArray = Array.isArray(optsAlias) ? optsAlias : [optsAlias];

return aliasArray.reduce((acc, alias) => {
return aliasArray.reduce((aliasPairs, alias) => {
const aliasKeys = Object.keys(alias);

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

acc.push(aliasPair);
const isKeyRegExp = isRegExp(key);
aliasPairs.push([
getAliasTarget(key, isKeyRegExp),
getAliasSubstitute(alias[key], isKeyRegExp),
]);
});

return acc;
return aliasPairs;
}, []);
}

Expand Down
61 changes: 61 additions & 0 deletions test/index.test.js
Expand Up @@ -492,6 +492,67 @@ describe('module-resolver', () => {
});
});

describe('with a function', () => {
const mockSubstitute = jest.fn();
const regExpSubsituteOpts = {
babelrc: false,
plugins: [
[plugin, {
alias: {
'basic-function': mockSubstitute,
'^@regexp-function/(.+)': mockSubstitute,
},
}],
],
};

beforeEach(() => {
mockSubstitute.mockClear();
});

it('should call the substitute with the right arguments (basic)', () => {
mockSubstitute.mockReturnValue('./test/testproject/test');

testWithImport(
'basic-function/something',
'./test/testproject/test',
regExpSubsituteOpts,
);

expect(mockSubstitute.mock.calls.length).toBe(1);

const execResult = Object.assign(
['basic-function/something', '/something'],
{
index: 0,
input: 'basic-function/something',
},
);
expect(mockSubstitute).toBeCalledWith(execResult);
});

it('should call the substitute with the right arguments (regexp)', () => {
mockSubstitute.mockReturnValue('./test/testproject/test');

testWithImport(
'@regexp-function/something',
'./test/testproject/test',
regExpSubsituteOpts,
);

expect(mockSubstitute.mock.calls.length).toBe(1);

const execResult = Object.assign(
['@regexp-function/something', 'something'],
{
index: 0,
input: '@regexp-function/something',
},
);
expect(mockSubstitute).toBeCalledWith(execResult);
});
});

describe('with the plugin applied twice', () => {
const doubleAliasTransformerOpts = {
babelrc: false,
Expand Down

0 comments on commit 9299d9a

Please sign in to comment.