Skip to content
This repository has been archived by the owner on Feb 18, 2023. It is now read-only.

Commit

Permalink
Merge 6fe6c29 into ec83dae
Browse files Browse the repository at this point in the history
  • Loading branch information
m59peacemaker committed Jul 25, 2016
2 parents ec83dae + 6fe6c29 commit ff98cb9
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 7 deletions.
61 changes: 54 additions & 7 deletions src/plugin.js
@@ -1,9 +1,38 @@
import { dirname, join, relative, isAbsolute } from 'path'
import slash from 'slash'

export default function () {
export default function ({types: t}) {
return {
visitor: {
CallExpression (path, state) {
if (path.node.callee.name !== 'require') { return }
const args = path.node.arguments
if (!args.length) { return }

const config = extractConfig(state)

const sourcePath = state.file.opts.filename

if (sourcePath === 'unknown') {
return
}

invariants(config)

const firstArg = traverseExpression(t, args[0])
if (!firstArg) { return }
const importPath = firstArg.value.raw || firstArg.value
if (isImportPathPrefixed(importPath, config.importPathPrefix)) {
let newValue = getNewValue(config, sourcePath, importPath)
newValue += importPath === config.importPathPrefix ? '/' : ''
if (typeof firstArg.value === 'object') {
firstArg.value.raw = newValue
firstArg.value.cooked = newValue
} else {
firstArg.value = newValue
}
}
},
ImportDeclaration (path, state) {
// config: {
// projectRoot: babel option sourceRoot or process.cwd as fallback
Expand All @@ -25,18 +54,36 @@ export default function () {
const importPath = path.node.source.value

if (isImportPathPrefixed(importPath, config.importPathPrefix)) {
const absoluteImportPath = getAbsoluteImportPath(importPath, config)

const absoluteSourcePath = getAbsoluteSourcePath(config.projectRoot, sourcePath)
const relativeImportPath = relative(dirname(absoluteSourcePath), absoluteImportPath)

path.node.source.value = './' + slash(relativeImportPath)
path.node.source.value = getNewValue(config, sourcePath, importPath)
}
}
}
}
}

function traverseExpression (t, arg) {
if (t.isStringLiteral(arg)) {
return arg
}
if (t.isBinaryExpression(arg)) {
return traverseExpression(t, arg.left)
}
if (t.isTemplateLiteral(arg)) {
return traverseExpression(t, arg.quasis[0])
}
if (t.isTemplateElement(arg)) {
return arg
}
return null
}

function getNewValue (config, sourcePath, importPath) {
const absoluteImportPath = getAbsoluteImportPath(importPath, config)
const absoluteSourcePath = getAbsoluteSourcePath(config.projectRoot, sourcePath)
const relativeImportPath = relative(dirname(absoluteSourcePath), absoluteImportPath)
return './' + slash(relativeImportPath)
}

function extractConfig (state) {
return {
projectRoot: state.file.opts.sourceRoot || process.cwd(),
Expand Down
71 changes: 71 additions & 0 deletions test/plugin.js
Expand Up @@ -17,6 +17,17 @@ describe('Plugin', () => {
expect(transformedCode.code).to.contain('\"~/dir/test\"')
})

it('without filename set (require)', () => {
const transformedCode = transform(
'const Test = require("~/dir/test")', {
sourceRoot: '/project/root/',
plugins: [ rootImportPlugin ]
}
)

expect(transformedCode.code).to.contain('\"~/dir/test\"')
})

it('when import path is not prefixed', () => {
const transformedCode = transform(
'import Test from "~/dir/test"', {
Expand All @@ -28,6 +39,18 @@ describe('Plugin', () => {

expect(transformedCode.code).to.contain('\"~/dir/test\"')
})

it('when require path does not start with string/template', () => {
const transformedCode = transform(
'const Test = require(myVar + "/foo")', {
filename: '/project/root/otherdir/test.js',
sourceRoot: '/project/root/',
plugins: [ rootImportPlugin ]
}
)

expect(transformedCode.code).to.contain('myVar + \"/foo\"')
})
})

describe('should transform the project relative path to a file relative path', () => {
Expand Down Expand Up @@ -89,6 +112,54 @@ describe('Plugin', () => {

expect(transformedCode.code).to.contain('\"./../dir/test\"')
})

it('for string require', () => {
const transformedCode = transform(
'const Test = require("~/dir/test")', {
filename: '/project/root/otherdir/test.js',
sourceRoot: '/project/root/',
plugins: [ rootImportPlugin ]
}
)

expect(transformedCode.code).to.contain('\"./../dir/test\"')
})

it('for a require with expression starting with prefix', () => {
const transformedCode = transform(
'const Test = require("~/" + "/test")', {
filename: '/project/root/otherdir/test.js',
sourceRoot: '/project/root/',
plugins: [ rootImportPlugin ]
}
)

expect(transformedCode.code).to.contain('\"./../" + "/test\"')
})

it('for require that starts with string and has variable', () => {
const transformedCode = transform(
'const Test = require("~/foo" + myVar + "/test")', {
filename: '/project/root/otherdir/test.js',
sourceRoot: '/project/root/',
plugins: [ rootImportPlugin ]
}
)

expect(transformedCode.code).to.contain('\"./../foo" + myVar + "/test\"')
})

it('for require with template string variable', () => {
const transformedCode = transform(
'const Test = require(`~/${myVar}`)', {
filename: '/project/root/otherdir/test.js',
sourceRoot: '/project/root/',
plugins: [ rootImportPlugin ]
}
)

expect(transformedCode.code).to.contain('`./../${ myVar }`')
})
})

describe('should throw an error', () => {
Expand Down

0 comments on commit ff98cb9

Please sign in to comment.