Skip to content

Commit

Permalink
fix(compiler-sfc): fix rewrite named export default (#1675)
Browse files Browse the repository at this point in the history
  • Loading branch information
underfin authored Jul 23, 2020
1 parent ee6828a commit 452edb7
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 3 deletions.
29 changes: 29 additions & 0 deletions packages/compiler-sfc/__tests__/rewriteDefault.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { rewriteDefault } from '../src'

describe('compiler sfc: rewriteDefault', () => {
test('without export default', () => {
expect(rewriteDefault(`export a = {}`, 'script')).toMatchInlineSnapshot(`
"export a = {}
const script = {}"
`)
})

test('rewrite export default', () => {
expect(
rewriteDefault(`export default {}`, 'script')
).toMatchInlineSnapshot(`"const script = {}"`)
})

test('rewrite export named default', () => {
expect(
rewriteDefault(
`const a = 1 \n export { a as b, a as default, a as c}`,
'script'
)
).toMatchInlineSnapshot(`
"const a = 1
export { a as b, a as c}
const script = a"
`)
})
})
28 changes: 25 additions & 3 deletions packages/compiler-sfc/src/rewriteDefault.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { parse, ParserPlugin } from '@babel/parser'
import MagicString from 'magic-string'

const defaultExportRE = /((?:^|\n|;)\s*)export default/
const defaultExportRE = /((?:^|\n|;)\s*)export(\s*)default/
const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)as(\s*)default/

/**
* Utility for rewriting `export default` in a script block into a varaible
Expand All @@ -12,25 +13,46 @@ export function rewriteDefault(
as: string,
parserPlugins?: ParserPlugin[]
): string {
if (!defaultExportRE.test(input)) {
if (!hasDefaultExport(input)) {
return input + `\nconst ${as} = {}`
}

const replaced = input.replace(defaultExportRE, `$1const ${as} =`)
if (!defaultExportRE.test(replaced)) {
if (!hasDefaultExport(replaced)) {
return replaced
}

// if the script somehow still contains `default export`, it probably has
// multi-line comments or template strings. fallback to a full parse.
const s = new MagicString(input)
const ast = parse(input, {
sourceType: 'module',
plugins: parserPlugins
}).program.body
ast.forEach(node => {
if (node.type === 'ExportDefaultDeclaration') {
s.overwrite(node.start!, node.declaration.start!, `const ${as} = `)
}
if (node.type === 'ExportNamedDeclaration') {
node.specifiers.forEach(specifier => {
if (
specifier.type === 'ExportSpecifier' &&
specifier.exported.name === 'default'
) {
const end = specifier.end!
s.overwrite(
specifier.start!,
input.charAt(end) === ',' ? end + 1 : end,
``
)
s.append(`\nconst ${as} = ${specifier.local.name}`)
}
})
}
})
return s.toString()
}

export function hasDefaultExport(input: string): boolean {
return defaultExportRE.test(input) || namedDefaultExportRE.test(input)
}

0 comments on commit 452edb7

Please sign in to comment.