Skip to content

Commit

Permalink
fix: undefined exports issues
Browse files Browse the repository at this point in the history
BREAKING CHANGE: If `__esModule` exists and `export default` only exists, add `module.exports`.
  • Loading branch information
59naga committed Jun 25, 2018
1 parent 3487ac1 commit c4aa1b0
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 24 deletions.
77 changes: 53 additions & 24 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,68 @@
class AssignmentReminder {
constructor () {
this.hasExportDefault = false
this.hasExportNamed = false
}
evaluateExpression (path, property = 'expression') {
// Not `exports.anything`, skip
if (!path.get(`${property}.left`).node || !path.get(`${property}.left.property`).node) {
return
}

const objectName = path.get(`${property}.left.object.name`).node
const propertyName = path.get(`${property}.left.property.name`).node
const name = `${objectName}.${propertyName}`
if (name === 'exports.default') {
this.hasExportDefault = true
} else if (objectName === 'exports') {
this.hasExportNamed = true
}
}
}

module.exports = ({types}) => ({
visitor: {
Program: {
CallExpression: {
exit (path) {
if (path.BABEL_PLUGIN_ADD_MODULE_EXPORTS) {
// Not `Object.defineProperty`, skip
if (path.get('callee.name').node) {
return
}

let hasExportDefault = false
let hasExportNamed = false
path.get('body').forEach((path) => {
if (path.isExportDefaultDeclaration()) {
hasExportDefault = true
return
const callee = `${path.get('callee.object.name').node}.${path.get('callee.property.name').node}`
const args = path.get('arguments').map(path => {
if (path.isStringLiteral()) {
return path.get('value').node
}
if (path.get('properties').length) {
return `${path.get('properties.0.key.name').node}:${path.get('properties.0.value.value').node}`
}
}).join(' ')

if (path.isExportNamedDeclaration()) {
if (path.node.specifiers.length === 1 && path.node.specifiers[0].exported.name === 'default') {
hasExportDefault = true
const isLegacyModule = `${callee}${args}` === 'Object.defineProperty __esModule value:true'
if (isLegacyModule) {
const reminder = new AssignmentReminder()
const program = path.parentPath.parentPath
program.get('body').forEach((path) => {
if (path.isVariableDeclaration()) {
reminder.evaluateExpression(path.get('declarations.0'), 'init')
} else {
hasExportNamed = true
if (path.isExpressionStatement() && path.get('expression').isAssignmentExpression()) {
reminder.evaluateExpression(path)
}
}
}
})
})

if (hasExportDefault && !hasExportNamed) {
path.pushContainer('body', [
types.expressionStatement(types.assignmentExpression(
'=',
types.memberExpression(types.identifier('module'), types.identifier('exports')),
types.memberExpression(types.identifier('exports'), types.stringLiteral('default'), true)
))
])
if (reminder.hasExportDefault && !reminder.hasExportNamed) {
program.pushContainer('body', [
types.expressionStatement(types.assignmentExpression(
'=',
types.memberExpression(types.identifier('module'), types.identifier('exports')),
types.memberExpression(types.identifier('exports'), types.stringLiteral('default'), true)
))
])
}
}

path.BABEL_PLUGIN_ADD_MODULE_EXPORTS = true
}
}
}
Expand Down
12 changes: 12 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import assert from 'assert'
import {transform as babelTransform} from 'babel-core'
import { testPlugin, equal } from './helpers'
import testCases from './spec'

Expand All @@ -11,6 +12,17 @@ describe('babel-plugin-add-module-exports', () => {
assert(module.default === 'default-entry')
}))

it('should not handle an pure esmodule', () => {
const code = `export default 'default-entry';`
const result = babelTransform(code, {
presets: [['env', {modules: false}]],
plugins: [
'./src/index.js'
]
})
assert(code === result.code)
})

it('plugin should export to module.exports(#31)', () => {
const plugin = require('../src')
assert(typeof plugin === 'function')
Expand Down

0 comments on commit c4aa1b0

Please sign in to comment.