Skip to content

Commit

Permalink
feat: basic support for rewiring require calls. fixes #145 (#145)
Browse files Browse the repository at this point in the history
  • Loading branch information
satya164 authored and zamotany committed Oct 21, 2017
1 parent 632c1fb commit a6297d6
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 30 deletions.
65 changes: 49 additions & 16 deletions src/babel/rewire-imports/__tests__/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,6 @@ function transpile(source, pluginOptions = {}, options = {}) {
}

describe('rewire-imports babel plugin', () => {
it('should throw error if there is a CJS import to linaria', () => {
expect(() => {
transpile(`
const linaria = require('linaria');
`);
}).toThrowError();
});

it('should not throw error if the CJS import is already rewired', () => {
expect(() => {
transpile(`
const linaria = require('linaria/build/index.runtime.js');
`);
}).not.toThrowError();
});

it('should rewire ESM import to linaria', () => {
const { code } = transpile(`
import { names } from 'linaria';
Expand All @@ -54,4 +38,53 @@ describe('rewire-imports babel plugin', () => {

expect(code).toMatch(`require('linaria')`);
});

it('should rewire CJS require to linaria', () => {
const { code } = transpile(`
const linaria = require('linaria');
`);

expect(code).toMatch(`require('linaria/build/index.runtime.js')`);
});

it('should rewire CJS require with ternary to linaria', () => {
const { code: consequent } = transpile(`
const linaria = require(dev ? 'linaria' : 'something');
`);
const { code: alternate } = transpile(`
const linaria = require(dev ? 'something' : 'linaria');
`);

expect(consequent).toMatch(
`require(dev ? 'linaria/build/index.runtime.js' : 'something')`
);
expect(alternate).toMatch(
`require(dev ? 'something' : 'linaria/build/index.runtime.js')`
);
});

it('should do nothing if CJS require is already rewired', () => {
const { code } = transpile(`
const linaria = require('linaria/build/index.runtime.js');
`);

expect(code).toMatch(`require('linaria/build/index.runtime.js')`);
});

it('should not rewire a member expression require to linaria', () => {
const { code } = transpile(`
const linaria = test.require('linaria');
`);

expect(code).toMatch(`test.require('linaria')`);
});

it('should skip rewiring if the require is inside prevaled source', () => {
const { code } = transpile(`
/* linaria-preval */
const linaria = require('linaria');
`);

expect(code).toMatch(`require('linaria')`);
});
});
46 changes: 32 additions & 14 deletions src/babel/rewire-imports/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
/* @flow */

import type { BabelTypes, NodePath, BabelVariableDeclarator } from '../types';
import type { BabelTypes, NodePath } from '../types';

type State = {
shouldSkip: boolean,
};

function getReplacement(value) {
return `${value}/build/index.runtime.js`.replace(/\/\//g, '/');
}

function isLinariaImport(value) {
try {
return require.resolve(value) === require.resolve('linaria');
Expand All @@ -27,24 +31,38 @@ export default ({ types }: { types: BabelTypes }) => ({
},
ImportDeclaration(path: NodePath<any>, state: State) {
if (!state.shouldSkip && isLinariaImport(path.node.source.value)) {
path.node.source.value = `${path.node.source
.value}/build/index.runtime.js`.replace(/\/\//g, '/');
path.node.source.value = getReplacement(path.node.source.value);
}
},
VariableDeclarator(
path: NodePath<BabelVariableDeclarator<any>>,
state: State
) {
CallExpression(path: NodePath<any>, state: State) {
if (
!state.shouldSkip &&
types.isCallExpression(path.node.init) &&
path.node.init.callee.name === 'require' &&
isLinariaImport(path.node.init.arguments[0].value)
path.node.callee.name === 'require' &&
path.node.arguments.length === 1
) {
// @TODO: it's very tricky to implement this for require
throw path.buildCodeFrameError(
"Linaria's rewire-imports plugin does not support require calls yet"
);
const argument = path.node.arguments[0];

if (types.isStringLiteral(argument)) {
if (isLinariaImport(argument.value)) {
argument.value = getReplacement(argument.value);
}
} else if (types.isConditionalExpression(argument)) {
if (
types.isStringLiteral(argument.consequent) &&
isLinariaImport(argument.consequent.value)
) {
argument.consequent.value = getReplacement(
argument.consequent.value
);
}

if (
types.isStringLiteral(argument.alternate) &&
isLinariaImport(argument.alternate.value)
) {
argument.alternate.value = getReplacement(argument.alternate.value);
}
}
}
},
},
Expand Down
9 changes: 9 additions & 0 deletions src/babel/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ export type BabelIdentifier = {
type: string,
};

export type BabelConditionalExpression = {
type: string,
test: any,
consequent: any,
alternate: any,
};

export type BabelJSXExpressionContainer = {
type: string,
expression: any,
Expand Down Expand Up @@ -126,13 +133,15 @@ export type BabelTypes = {
BabelTaggedTemplateExpression<any>
>,
isCallExpression: BabelIsTypeFunction<BabelCallExpression>,
isConditionalExpression: BabelIsTypeFunction<BabelConditionalExpression>,
isIdentifier: BabelIsTypeFunction<BabelIdentifier>,
isJSXExpressionContainer: BabelIsTypeFunction<BabelJSXExpressionContainer>,
isJSXIdentifier: BabelIsTypeFunction<BabelJSXIdentifier>,
isJSXSpreadAttribute: BabelIsTypeFunction<BabelJSXSpreadAttribute>,
isMemberExpression: BabelIsTypeFunction<BabelMemberExpression>,
isObjectExpression: BabelIsTypeFunction<BabelObjectExpression>,
isObjectPattern: BabelIsTypeFunction<BabelObjectPattern>,
isStringLiteral: BabelIsTypeFunction<BabelStringLiteral>,
isVariableDeclaration: BabelIsTypeFunction<BabelVariableDeclaration>,
};

Expand Down

0 comments on commit a6297d6

Please sign in to comment.