Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow non-module resolves #390

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/mapPath.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import defaultResolvePath from './resolvePath';

export default function mapPathString(nodePath, state) {
export default function mapPathString(nodePath, state, resolveOpts) {
if (!state.types.isStringLiteral(nodePath)) {
return;
}
Expand All @@ -9,7 +9,7 @@ export default function mapPathString(nodePath, state) {
const currentFile = state.file.opts.filename;
const resolvePath = state.normalizedOpts.customResolvePath || defaultResolvePath;

const modulePath = resolvePath(sourcePath, currentFile, state.opts);
const modulePath = resolvePath(sourcePath, currentFile, state.opts, resolveOpts);
if (modulePath) {
if (nodePath.node.pathResolved) {
return;
Expand Down
50 changes: 34 additions & 16 deletions src/normalizeOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,20 @@ import pkgUp from 'pkg-up';
import { escapeRegExp } from './utils';

const defaultExtensions = ['.js', '.jsx', '.es', '.es6', '.mjs'];
const defaultTransformedFunctions = [
'require',
'require.resolve',
'System.import',
const defaultTransformFunctions = [
{ pattern: 'require', isModulePath: true },
{ pattern: 'require.resolve', isModulePath: true },
{ pattern: 'System.import', isModulePath: true },

// Jest methods
'jest.genMockFromModule',
'jest.mock',
'jest.unmock',
'jest.doMock',
'jest.dontMock',
'jest.setMock',
'require.requireActual',
'require.requireMock',
{ pattern: 'jest.genMockFromModule', isModulePath: true },
{ pattern: 'jest.mock', isModulePath: true },
{ pattern: 'jest.unmock', isModulePath: true },
{ pattern: 'jest.doMock', isModulePath: true },
{ pattern: 'jest.dontMock', isModulePath: true },
{ pattern: 'jest.setMock', isModulePath: true },
{ pattern: 'require.requireActual', isModulePath: true },
{ pattern: 'require.requireMock', isModulePath: true },
];

function isRegExp(string) {
Expand Down Expand Up @@ -122,12 +122,30 @@ function normalizeAlias(optsAlias) {
}, []);
}

function normalizeTransformedFunctions(optsTransformFunctions) {
function normalizeTransformFunctionsElement(optsTransformFunction) {
let pattern;
let opts;
if (Array.isArray(optsTransformFunction)) {
[pattern, opts] = optsTransformFunction;
} else {
[pattern, opts] = [optsTransformFunction, {}];
}

const finalOpts = { pattern, isModulePath: true };
if (opts.isModulePath !== undefined) {
finalOpts.isModulePath = opts.isModulePath;
}

return finalOpts;
}

function normalizeTransformFunctions(optsTransformFunctions) {
if (!optsTransformFunctions) {
return defaultTransformedFunctions;
return defaultTransformFunctions;
}

return [...defaultTransformedFunctions, ...optsTransformFunctions];
return [...defaultTransformFunctions,
...optsTransformFunctions.map(normalizeTransformFunctionsElement)];
}

function normalizeLoglevel(optsLoglevel) {
Expand All @@ -143,7 +161,7 @@ export default createSelector(
const root = normalizeRoot(opts.root, cwd);
const alias = normalizeAlias(opts.alias);
const loglevel = normalizeLoglevel(opts.loglevel);
const transformFunctions = normalizeTransformedFunctions(opts.transformFunctions);
const transformFunctions = normalizeTransformFunctions(opts.transformFunctions);
const extensions = opts.extensions || defaultExtensions;
const stripExtensions = opts.stripExtensions || extensions;

Expand Down
28 changes: 19 additions & 9 deletions src/resolvePath.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,24 @@ function getRelativePath(sourcePath, currentFile, absFileInRoot, opts) {
return toLocalPath(toPosixPath(relativePath));
}

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

root.some((basedir) => {
resolvedSourceFile = nodeResolvePath(`./${sourcePath}`, basedir, extensions);
if (isModulePath) {
resolvedSourceFile = nodeResolvePath(`./${sourcePath}`, basedir, extensions);
} else {
resolvedSourceFile = path.resolve(basedir, `./${sourcePath}`);
}
return resolvedSourceFile !== null;
});

return resolvedSourceFile;
}

function resolvePathFromRootConfig(sourcePath, currentFile, opts) {
const absFileInRoot = findPathInRoots(sourcePath, opts);
function resolvePathFromRootConfig(sourcePath, currentFile, opts, resolveOpts) {
const absFileInRoot = findPathInRoots(sourcePath, opts, resolveOpts);

if (!absFileInRoot) {
return null;
Expand All @@ -46,7 +50,7 @@ function checkIfPackageExists(modulePath, currentFile, extensions, loglevel) {
}
}

function resolvePathFromAliasConfig(sourcePath, currentFile, opts) {
function resolvePathFromAliasConfig(sourcePath, currentFile, opts, { isModulePath = true } = {}) {
let aliasedSourceFile;

opts.alias.find(([regExp, substitute]) => {
Expand All @@ -73,7 +77,10 @@ function resolvePathFromAliasConfig(sourcePath, currentFile, opts) {
}
return asf;
})
.find(src => nodeResolvePath(src, path.dirname(currentFile), opts.extensions));
.find(src => {
return !isModulePath
|| nodeResolvePath(src, path.dirname(currentFile), opts.extensions);
});
}

if (isRelativePath(aliasedSourceFile)) {
Expand All @@ -82,7 +89,7 @@ function resolvePathFromAliasConfig(sourcePath, currentFile, opts) {
);
}

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

Expand All @@ -94,7 +101,9 @@ const resolvers = [
resolvePathFromRootConfig,
];

export default function resolvePath(sourcePath, currentFile, opts) {
export default function resolvePath(
sourcePath, currentFile, opts, { isModulePath = true } = {},
) {
if (isRelativePath(sourcePath)) {
return sourcePath;
}
Expand All @@ -107,7 +116,8 @@ export default function resolvePath(sourcePath, currentFile, opts) {
let resolvedPath = null;

resolvers.some((resolver) => {
resolvedPath = resolver(sourcePath, absoluteCurrentFile, normalizedOpts);
resolvedPath = resolver(
sourcePath, absoluteCurrentFile, normalizedOpts, { isModulePath });
return resolvedPath !== null;
});

Expand Down
10 changes: 7 additions & 3 deletions src/transformers/call.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ export default function transformCall(nodePath, state) {
}

const calleePath = nodePath.get('callee');
const isNormalCall = state.normalizedOpts.transformFunctions.some(pattern =>
const transformFunction = state.normalizedOpts.transformFunctions.find(({ pattern }) =>
matchesPattern(state.types, calleePath, pattern)
);

if (isNormalCall || isImportCall(state.types, nodePath)) {
if (transformFunction) {
state.moduleResolverVisited.add(nodePath);
mapPathString(nodePath.get('arguments.0'), state);
const { isModulePath } = transformFunction;
mapPathString(nodePath.get('arguments.0'), state, { isModulePath });
} else if (isImportCall(state.types, nodePath)) {
state.moduleResolverVisited.add(nodePath);
mapPathString(nodePath.get('arguments.0'), state, { isModulePath: true });
}
}
2 changes: 1 addition & 1 deletion src/transformers/import.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ export default function transformImport(nodePath, state) {
}
state.moduleResolverVisited.add(nodePath);

mapPathString(nodePath.get('source'), state);
mapPathString(nodePath.get('source'), state, { isModulePath: true });
}
33 changes: 24 additions & 9 deletions test/custom-call.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import plugin from '../src';


const calls = [
'customMethod.something',
'customMethod.Module',
'customMethod.NonModule',
];

describe('custom calls', () => {
Expand All @@ -16,7 +17,8 @@ describe('custom calls', () => {
test: './test/testproject/test',
},
transformFunctions: [
'customMethod.something',
'customMethod.Module',
['customMethod.NonModule', { isModulePath: false }],
],
}],
],
Expand Down Expand Up @@ -59,13 +61,6 @@ describe('custom calls', () => {
expect(result.code).toBe(`${name}(path, ...args);`);
});

it('should handle an empty path', () => {
const code = `${name}('', ...args);`;
const result = transform(code, transformerOpts);

expect(result.code).toBe(`${name}('', ...args);`);
});

it('should ignore the call if the method name is not fully matched (suffix)', () => {
const code = `${name}.after("components/Sidebar/Footer", ...args);`;
const result = transform(code, transformerOpts);
Expand All @@ -81,4 +76,24 @@ describe('custom calls', () => {
});
});
});

describe('customMethod.Module', () => {
const name = 'customMethod.Module';
it('should handle an empty path', () => {
const code = `${name}('', ...args);`;
const result = transform(code, transformerOpts);

expect(result.code).toBe(`${name}('', ...args);`);
});
});

describe('customMethod.NonModule', () => {
const name = 'customMethod.NonModule';
it('should handle an empty path', () => {
const code = `${name}('', ...args);`;
const result = transform(code, transformerOpts);

expect(result.code).toBe(`${name}("./test/testproject/src", ...args);`);
});
});
});
22 changes: 22 additions & 0 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ describe('module-resolver', () => {
expect(result.code).toBe(`import something from "${output}";`);
}

function testWithFunction(functionName, source, output, transformerOpts) {
const code = `${functionName}("${source}");`;
const result = transform(code, transformerOpts);

expect(result.code).toBe(`${functionName}("${output}");`);
}

describe('exports', () => {
describe('resolvePath', () => {
it('should be a function', () => {
Expand Down Expand Up @@ -636,9 +643,13 @@ describe('module-resolver', () => {
plugins: [
[pluginWithMock, {
alias: {
'~': './test/testproject/src',
legacy: 'npm:legacy',
'non-existing': 'this-package-does-not-exist',
},
transformFunctions: [
['customResolvePath', { isModulePath: false }],
],
}],
],
};
Expand Down Expand Up @@ -670,6 +681,17 @@ describe('module-resolver', () => {
expect(mockWarn).toBeCalledWith(`Could not resolve "this-package-does-not-exist/lib" in file ${fileName}.`);
});

it("shouldn't print a warning for a non-module resolve", () => {
testWithFunction(
'customResolvePath',
'~/libs',
'./test/testproject/src/libs',
missingAliasTransformerOpts,
);

expect(mockWarn.mock.calls.length).toBe(0);
});

describe('production environment', () => {
beforeEach(() => {
process.env.NODE_ENV = 'production';
Expand Down