type RawScript = [ 'normal' | 'setup' , string [ ] ] ; export function extractScripts ( source ) { const lines = source . split ( '\n' ) ; const rawScripts = extractScriptLines ( lines ) ; const normalScripts = rawScripts . filter ( ( [ type ] ) => type === 'normal' ) ; const setupScripts = rawScripts . filter ( ( [ type ] ) => type === 'setup' ) ; const finalLines = [ ] ; for ( const rawScript of normalScripts ) { finalLines . push ( ... rawScript [ 1 ] ) ; } let exportIndex = finalLines . findIndex ( line => isExportDefault ( line ) ) ; if ( exportIndex === - 1 ) { finalLines . unshift ( 'import { defineComponent } from "vue"' ) ; exportIndex = finalLines . length ; finalLines . push ( 'export default defineComponent({' , '})' ) ; } if ( setupScripts . length > 0 ) { finalLines . splice ( exportIndex + 1 , 0 , 'setup () {' , '},' ) ; exportIndex ++ ; } const setupVariables = [ ] ; for ( const rawScript of setupScripts ) { finalLines . splice ( exportIndex + 1 , 0 , ... rawScript [ 1 ] ) ; exportIndex += rawScript [ 1 ] . length ; for ( const line of rawScript [ 1 ] ) { const variable = getVariableName ( line ) ; if ( variable ) { setupVariables . push ( variable ) ; } } } if ( setupVariables . length > 0 ) { finalLines . splice ( exportIndex + 1 , 0 , `return {${ setupVariables . join ( ',' ) }}` ) ; exportIndex ++ ; } return finalLines . join ( '\n' ) ; } export function isScriptTagStart ( line ) { return line . trim ( ) . startsWith ( '<script' ) ; } export function isScriptTagEnd ( line ) { return line . trim ( ) === '</script>' ; } export function isSetupScript ( line ) { return line . includes ( 'setup' ) ; } export function isExportDefault ( line ) { return line . trim ( ) . startsWith ( 'export default' ) ; } export function getVariableName ( line ) { const matched = /(var|const|let)\s+([\w\d_]+)/ . exec ( line ) ; if ( matched ) { return matched [ 2 ] ; } return null ; } export function extractScriptLines ( lines ) { let depth = 0 ; const scripts = [ ] ; let scriptLines = [ ] ; for ( const line of lines ) { if ( isScriptTagStart ( line ) ) { depth ++ ; if ( depth === 1 ) { scriptLines = [ ] ; scripts . push ( [ isSetupScript ( line ) ? 'setup' : 'normal' , scriptLines ] ) ; } } else if ( isScriptTagEnd ( line ) ) { depth -- ; } else if ( depth > 0 ) { scriptLines . push ( line ) ; } } if ( depth > 0 ) { throw new Error ( 'unclosed script tag' ) ; } return scripts ; }