| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 |
- import { parse, ParserPlugin } from '@babel/parser'
- import MagicString from 'magic-string'
- const defaultExportRE = /((?:^|\n|;)\s*)export(\s*)default/
- const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)as(\s*)default/s
- const exportDefaultClassRE = /((?:^|\n|;)\s*)export\s+default\s+class\s+([\w$]+)/
- /**
- * Utility for rewriting `export default` in a script block into a variable
- * declaration so that we can inject things into it
- */
- export function rewriteDefault(
- input: string,
- as: string,
- parserPlugins?: ParserPlugin[]
- ): string {
- if (!hasDefaultExport(input)) {
- return input + `\nconst ${as} = {}`
- }
- let replaced: string | undefined
- const classMatch = input.match(exportDefaultClassRE)
- if (classMatch) {
- replaced =
- input.replace(exportDefaultClassRE, '$1class $2') +
- `\nconst ${as} = ${classMatch[2]}`
- } else {
- replaced = input.replace(defaultExportRE, `$1const ${as} =`)
- }
- 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.type === 'Identifier' &&
- 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)
- }
|