| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- 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') {
- if (node.declaration.type === 'ClassDeclaration') {
- s.overwrite(node.start!, node.declaration.id.start!, `class `)
- s.append(`\nconst ${as} = ${node.declaration.id.name}`)
- } else {
- s.overwrite(node.start!, node.declaration.start!, `const ${as} = `)
- }
- }
- if (node.type === 'ExportNamedDeclaration') {
- for (const specifier of node.specifiers) {
- if (
- specifier.type === 'ExportSpecifier' &&
- specifier.exported.type === 'Identifier' &&
- specifier.exported.name === 'default'
- ) {
- if (node.source) {
- if (specifier.local.name === 'default') {
- const end = specifierEnd(input, specifier.local.end!, node.end!)
- s.prepend(
- `import { default as __VUE_DEFAULT__ } from '${node.source.value}'\n`
- )
- s.overwrite(specifier.start!, end, ``)
- s.append(`\nconst ${as} = __VUE_DEFAULT__`)
- continue
- } else {
- const end = specifierEnd(
- input,
- specifier.exported.end!,
- node.end!
- )
- s.prepend(
- `import { ${input.slice(
- specifier.local.start!,
- specifier.local.end!
- )} } from '${node.source.value}'\n`
- )
- s.overwrite(specifier.start!, end, ``)
- s.append(`\nconst ${as} = ${specifier.local.name}`)
- continue
- }
- }
- const end = specifierEnd(input, specifier.end!, node.end!)
- s.overwrite(specifier.start!, end, ``)
- s.append(`\nconst ${as} = ${specifier.local.name}`)
- }
- }
- }
- })
- return s.toString()
- }
- export function hasDefaultExport(input: string): boolean {
- return defaultExportRE.test(input) || namedDefaultExportRE.test(input)
- }
- function specifierEnd(input: string, end: number, nodeEnd: number | null) {
- // export { default , foo } ...
- let hasCommas = false
- let oldEnd = end
- while (end < nodeEnd!) {
- if (/\s/.test(input.charAt(end))) {
- end++
- } else if (input.charAt(end) === ',') {
- end++
- hasCommas = true
- break
- } else if (input.charAt(end) === '}') {
- break
- }
- }
- return hasCommas ? end : oldEnd
- }
|