Skip to content

Commit

Permalink
Merge pull request #66 from tyler-johnson/babel-7
Browse files Browse the repository at this point in the history
upgrade for babel 7
  • Loading branch information
59naga committed Sep 11, 2018
2 parents d76d035 + 3d934a2 commit b56a9a4
Show file tree
Hide file tree
Showing 5 changed files with 785 additions and 112 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
"postversion": "git push --follow-tags && conventional-github-releaser -p angular -r 0"
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/plugin-proposal-export-default-from": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"babel-eslint": "^8.2.6",
Expand Down
69 changes: 50 additions & 19 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,44 @@

module.exports = ({ template }) => {
let pluginOptions

function addModuleExportsDefaults(path) {
const finder = new ExportsFinder(path)
if (!finder.isOnlyExportsDefault()) {
return
}
if (finder.isAmd()) {
return
}
const rootPath = finder.getRootPath()

// HACK: `path.node.body.push` instead of path.pushContainer(due doesn't work in Plugin.post)
rootPath.node.body.push(template('module.exports = exports.default')())
if (pluginOptions.addDefaultProperty) {
rootPath.node.body.push(template('module.exports.default = exports.default')())
}
}

const ExportsDefaultVisitor = {
AssignmentExpression(path) {
if (path.get('left').matchesPattern('exports.default')) {
const finder = new ExportsFinder(path)
if (!finder.isOnlyExportsDefault()) {
return
}
if (finder.isAmd()) {
return
}
const rootPath = finder.getRootPath()
CallExpression(path) {
if (!path.get('callee').matchesPattern('Object.defineProperty')) {
return
}

// HACK: `path.node.body.push` instead of path.pushContainer(due doesn't work in Plugin.post)
rootPath.node.body.push(template('module.exports = exports.default')())
if (pluginOptions.addDefaultProperty) {
rootPath.node.body.push(template('module.exports.default = exports.default')())
}
const [identifier, prop] = path.get('arguments')
const objectName = identifier.get('name').node
const propertyName = prop.get('value').node

if ((objectName === 'exports' || objectName === '_exports') && propertyName === 'default') {
addModuleExportsDefaults(path)
}
},
AssignmentExpression(path) {
if (
path.get('left').matchesPattern('exports.default') ||
path.get('left').matchesPattern('_exports.default')
) {
addModuleExportsDefaults(path)
}
}
}
Expand All @@ -48,7 +69,9 @@ class ExportsFinder {
}

getRootPath() {
return this.path.parentPath.parentPath
return this.path.findParent(path => {
return path.key === 'body' || !path.parentPath
})
}

isOnlyExportsDefault() {
Expand Down Expand Up @@ -81,7 +104,7 @@ class ExportsFinder {

const objectName = path.get(`${property}.left.object.name`).node
const propertyName = path.get(`${property}.left.property.name`).node
if (objectName === 'exports') {
if (objectName === 'exports' || objectName === '_exports') {
if (propertyName === 'default') {
this.hasExportsDefault = true
} else if (propertyName !== '__esModule') {
Expand All @@ -104,8 +127,16 @@ class ExportsFinder {
const [identifier, prop] = path.get('arguments')
const objectName = identifier.get('name').node
const propertyName = prop.get('value').node
if (objectName === 'exports' && propertyName !== '__esModule') {
self.hasExportsNamed = true

if (
(objectName === 'exports' || objectName === '_exports') &&
propertyName !== '__esModule'
) {
if (propertyName === 'default') {
self.hasExportsDefault = true
} else {
self.hasExportsNamed = true
}
}
}
})
Expand Down
7 changes: 3 additions & 4 deletions test/helpers.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import vm from 'vm'
import util from 'util'
import { transform as babelTransform } from 'babel-core'
import assert from 'assert'

export function createSandbox() {
Expand Down Expand Up @@ -34,7 +33,7 @@ export function createSandboxAmd() {
return sandbox
}

export function testPlugin(code, options, fn, useAmdSandbox = false) {
export function testPlugin(babelTransform, code, options, fn, useAmdSandbox = false) {
const result = babelTransform(code, options)
const sandbox = useAmdSandbox ? createSandboxAmd() : createSandbox()

Expand Down Expand Up @@ -64,8 +63,8 @@ function equalObject(actual, expected, previouslyChecked) {
previouslyChecked.push(expected)

// Check if both have the same properties
const actualKeys = Object.keys(actual)
const expectedKeys = Object.keys(expected)
const actualKeys = Object.keys(actual).sort()
const expectedKeys = Object.keys(expected).sort()
if (Array.isArray(expected)) {
assert(actual.length === expected.length)
} else {
Expand Down
193 changes: 108 additions & 85 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,102 +1,125 @@
import assert from 'assert'
import { transform as babelTransform } from 'babel-core'
import { transform as babelTransform7 } from '@babel/core'
import { testPlugin, equal } from './helpers'
import testCases from './spec'

describe('babel-plugin-add-module-exports', () => {
it('should not export default to `module.exports` by default.', () =>
testPlugin(
testCases[0].code,
{
presets: ['env']
},
module => {
assert(module !== 'default-entry')
assert(module.default === 'default-entry')
}
))
const babelVersions = {
'babel@6': babelTransform,
'babel@7': babelTransform7
}

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']
})
Object.keys(babelVersions).forEach(ver => {
const transform = babelVersions[ver]
const env = ver === 'babel@6' ? 'env' : '@babel/preset-env'

// use code comparison instead of vm.runInNewContext(doesn't work `export` syntax)
assert(code === result.code)
})
describe('babel-plugin-add-module-exports ' + ver, () => {
it('should not export default to `module.exports` by default.', () =>
testPlugin(
transform,
testCases[0].code,
{
presets: [env]
},
module => {
assert(module !== 'default-entry')
assert(module.default === 'default-entry')
}
))

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

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

it('should handle duplicated plugin references (#1)', () =>
testPlugin(
testCases[0].code,
{
presets: ['env'],
plugins: ['./src/index.js', './src/index.js', './src/index.js']
},
(module, code) => {
assert(module === 'default-entry')

// @see https://github.com/59naga/babel-plugin-add-module-exports/issues/12#issuecomment-157023722
assert(module.default === undefined)

assert(
code ===
`"use strict";\n\nObject.defineProperty(exports, "__esModule", {\n value: true\n});\nexports.default = "default-entry";\nmodule.exports = exports.default;`
)
}
))
})

it('should export with `babel-plugin-rewire` (#19)', () =>
testPlugin(
"export default { stuff: 'things' }",
{
presets: ['react', 'env'],
plugins: ['./src/index.js', 'rewire']
},
module => {
assert(module.stuff === 'things')
}
))
// use code comparison instead of vm.runInNewContext(doesn't work `export` syntax)
assert(code === result.code)
})

testCases.forEach(testCase =>
it(`should ${testCase.name}`, () =>
it('should not handle an amd module', () =>
testPlugin(
testCase.code,
transform,
`export default 'default-entry';`,
{
presets: [['env', testCase.env]],
plugins: [
'transform-export-extensions', // use export-from syntax
['./src/index.js', testCase.options]
]
presets: [[env, { modules: 'amd' }]],
plugins: ['./src/index.js']
},
module => {
// assert module root (module.exports) object
equal(module, testCase.expected.module)

// assert each common entry is exported without error
Object.keys(testCase.expected.exports).forEach(key =>
equal(module[key], testCase.expected.exports[key])
)
}
assert(module.default === 'default-entry')
},
true
))
)

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

if (ver === 'babel@6') {
// babel 7 throws an error with duplicate plugins
it('should handle duplicated plugin references (#1)', () =>
testPlugin(
transform,
testCases[0].code,
{
presets: [env],
plugins: ['./src/index.js', './src/index.js', './src/index.js']
},
(module, code) => {
assert(module === 'default-entry')

// @see https://github.com/59naga/babel-plugin-add-module-exports/issues/12#issuecomment-157023722
assert(module.default === undefined)

assert(
code ===
`"use strict";\n\nObject.defineProperty(exports, "__esModule", {\n value: true\n});\nexports.default = "default-entry";\nmodule.exports = exports.default;`
)
}
))

// rewire hasn't been updated for babel 7
// https://github.com/speedskater/babel-plugin-rewire/issues/209
it('should export with `babel-plugin-rewire` (#19)', () =>
testPlugin(
transform,
"export default { stuff: 'things' }",
{
presets: ['react', env],
plugins: ['./src/index.js', 'rewire']
},
module => {
assert(module.stuff === 'things')
}
))
}

testCases.forEach(testCase =>
it(`should ${testCase.name}`, () =>
testPlugin(
transform,
testCase.code,
{
presets: [[env, testCase.env]],
plugins: [
ver === 'babel@6' // use export-from syntax
? 'transform-export-extensions'
: '@babel/plugin-proposal-export-default-from',
['./src/index.js', testCase.options]
]
},
module => {
// assert module root (module.exports) object
equal(module, testCase.expected.module)

// assert each common entry is exported without error
Object.keys(testCase.expected.exports).forEach(key =>
equal(module[key], testCase.expected.exports[key])
)
}
))
)
})
})
Loading

0 comments on commit b56a9a4

Please sign in to comment.