Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 79 additions & 1 deletion packages/compiler-sfc/__tests__/rewriteDefault.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { rewriteDefault } from '../src'
import { parse } from '@babel/parser'
import { compileScript, parse as parseSFC, rewriteDefault } from '../src'

describe('compiler sfc: rewriteDefault', () => {
test('without export default', () => {
Expand Down Expand Up @@ -79,6 +80,83 @@ describe('compiler sfc: rewriteDefault', () => {
`)
})

describe.each([
'/* comma, brace } */',
'// comma, brace }\n',
'// comma, brace }\r',
'// comma, brace }\r\n',
'// comma, brace }\u2028',
'// comma, brace }\u2029',
])('trailing export specifier comment %s', comment => {
test.each([
[`a as default ${comment}`, []],
[`a as default ${comment}, a as b`, ['b']],
[`a as b, a as default ${comment}, a as c`, ['b', 'c']],
[`a as b, a as default ${comment}`, ['b']],
] as const)('rewrite local exports: %s', (specifiers, names) => {
const output = rewriteDefault(
`const a = 1\nexport { ${specifiers} }`,
'script',
)
const ast = parse(output, { sourceType: 'module' })
const exports = ast.program.body.find(
node => node.type === 'ExportNamedDeclaration',
)!

expect(exports.specifiers.map(specifier => specifier.exported)).toEqual(
names.map(name => expect.objectContaining({ name })),
)
expect(output).toContain('const script = a')
})

test.each(['default', 'default as default', 'foo as default'])(
'rewrite re-exports: %s',
specifier => {
const output = rewriteDefault(
`export { ${specifier} ${comment}, bar } from './index.js'`,
'script',
)
const ast = parse(output, { sourceType: 'module' })
const exports = ast.program.body.find(
node => node.type === 'ExportNamedDeclaration',
)!

expect(exports.specifiers).toHaveLength(1)
expect(exports.specifiers[0].exported).toMatchObject({ name: 'bar' })
expect(exports.source).toMatchObject({ value: './index.js' })
expect(output).toContain('const script = __VUE_DEFAULT__')
},
)
})

test('rewrite an explicitly aliased default re-export', () => {
expect(
rewriteDefault(
`export { default as default } from './index.js'`,
'script',
),
).toBe(
`import { default as __VUE_DEFAULT__ } from './index.js'\n` +
`export { } from './index.js'\nconst script = __VUE_DEFAULT__`,
)
})

test('compile a normal script with a trailing export specifier comment', () => {
const { descriptor } = parseSFC(
`<script>const App = {}; export { App as default /* comma, brace } */ }</script>`,
)
const compiled = compileScript(descriptor, {
id: 'test',
genDefaultAs: '_sfc_main',
})
const ast = parse(compiled.content, { sourceType: 'module' })

expect(ast.program.body[ast.program.body.length - 1]).toMatchObject({
type: 'VariableDeclaration',
declarations: [{ id: { name: '_sfc_main' }, init: { name: 'App' } }],
})
})

test('export named default multiline /w comments', () => {
expect(
rewriteDefault(
Expand Down
14 changes: 11 additions & 3 deletions packages/compiler-sfc/src/rewriteDefault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export function rewriteDefaultAST(
s.prepend(
`import { default as __VUE_DEFAULT__ } from '${node.source.value}'\n`,
)
const end = specifierEnd(s, specifier.local.end!, node.end!)
const end = specifierEnd(s, specifier.end!, node.end!)
s.remove(specifier.start!, end)
s.append(`\nconst ${as} = __VUE_DEFAULT__`)
continue
Expand All @@ -73,7 +73,7 @@ export function rewriteDefaultAST(
specifier.local.end!,
)} as __VUE_DEFAULT__ } from '${node.source.value}'\n`,
)
const end = specifierEnd(s, specifier.exported.end!, node.end!)
const end = specifierEnd(s, specifier.end!, node.end!)
s.remove(specifier.start!, end)
s.append(`\nconst ${as} = __VUE_DEFAULT__`)
continue
Expand Down Expand Up @@ -112,11 +112,19 @@ function specifierEnd(s: MagicString, end: number, nodeEnd: number | null) {
while (end < nodeEnd!) {
if (/\s/.test(s.slice(end, end + 1))) {
end++
} else if (s.slice(end, end + 2) === '/*') {
const commentEnd = s.original.indexOf('*/', end + 2)
end = commentEnd === -1 ? nodeEnd! : commentEnd + 2
} else if (s.slice(end, end + 2) === '//') {
end += 2
while (end < nodeEnd! && !/[\r\n\u2028\u2029]/.test(s.original[end])) {
end++
}
} else if (s.slice(end, end + 1) === ',') {
end++
hasCommas = true
break
} else if (s.slice(end, end + 1) === '}') {
} else {
break
}
}
Expand Down