@@ -9,10 +9,12 @@ import type { TemplateCodegenContext } from '../template/context';
99import { endOfLine , generateSfcBlockSection , newLine } from '../utils' ;
1010import { endBoundary , startBoundary } from '../utils/boundary' ;
1111import { createScriptCodegenContext , type ScriptCodegenContext } from './context' ;
12- import { generateScriptSetup , generateScriptSetupImports } from './scriptSetup' ;
12+ import { generateGeneric , generateScriptSetupImports , generateSetupFunction } from './scriptSetup' ;
1313import { generateSrc } from './src' ;
1414import { generateTemplate } from './template' ;
1515
16+ const exportExpression = `{} as typeof ${ names . _export } ` ;
17+
1618export interface ScriptCodegenOptions {
1719 ts : typeof ts ;
1820 vueCompilerOptions : VueCompilerOptions ;
@@ -35,47 +37,129 @@ export { generate as generateScript };
3537
3638function generate ( options : ScriptCodegenOptions ) {
3739 const context = createScriptCodegenContext ( options ) ;
38- const codegen = generateScript ( options , context ) ;
40+ const codegen = generateWorker ( options , context ) ;
3941
4042 return {
4143 ...context ,
4244 codes : [ ...codegen ] ,
4345 } ;
4446}
4547
46- function * generateScript (
48+ function * generateWorker (
4749 options : ScriptCodegenOptions ,
4850 ctx : ScriptCodegenContext ,
4951) : Generator < Code > {
5052 yield * generateGlobalTypesReference ( options ) ;
5153
52- if ( options . scriptSetup && options . scriptSetupRanges ) {
53- yield * generateScriptSetupImports ( options . scriptSetup , options . scriptSetupRanges ) ;
54+ const { script, scriptRanges, scriptSetup, scriptSetupRanges, vueCompilerOptions } = options ;
55+
56+ if ( scriptSetup && scriptSetupRanges ) {
57+ yield * generateScriptSetupImports ( scriptSetup , scriptSetupRanges ) ;
5458 }
55- if ( options . script && options . scriptRanges ) {
56- const { exportDefault, componentOptions } = options . scriptRanges ;
57- if ( options . scriptSetup && options . scriptSetupRanges ) {
58- if ( exportDefault ) {
59- yield * generateSfcBlockSection ( options . script , 0 , exportDefault . start , codeFeatures . all , true ) ;
60- yield * generateScriptSetup ( options , ctx , options . scriptSetup , options . scriptSetupRanges ) ;
61- }
62- else {
63- yield * generateSfcBlockSection ( options . script , 0 , options . script . content . length , codeFeatures . all , true ) ;
64- yield * generateScriptSetup ( options , ctx , options . scriptSetup , options . scriptSetupRanges ) ;
65- }
59+ if ( script ?. src ) {
60+ yield * generateSrc ( script . src ) ;
61+ }
62+
63+ // <script> + <script setup>
64+ if ( script && scriptRanges && scriptSetup && scriptSetupRanges ) {
65+ // <script> head
66+ const { exportDefault, componentOptions } = scriptRanges ;
67+ if ( exportDefault ) {
68+ yield * generateSfcBlockSection ( script , 0 , exportDefault . start , codeFeatures . all , true ) ;
69+ }
70+ else {
71+ yield * generateSfcBlockSection ( script , 0 , script . content . length , codeFeatures . all , true ) ;
72+ }
73+
74+ // <script setup>
75+ yield * generateExportDeclareEqual ( scriptSetup ) ;
76+ if ( scriptSetup . generic ) {
77+ yield * generateGeneric (
78+ options ,
79+ ctx ,
80+ scriptSetup ,
81+ scriptSetupRanges ,
82+ scriptSetup . generic ,
83+ generateSetupFunction (
84+ options ,
85+ ctx ,
86+ scriptSetup ,
87+ scriptSetupRanges ,
88+ generateTemplate ( options , ctx ) ,
89+ ) ,
90+ ) ;
91+ }
92+ else {
93+ yield `await (async () => {${ newLine } ` ;
94+ yield * generateSetupFunction (
95+ options ,
96+ ctx ,
97+ scriptSetup ,
98+ scriptSetupRanges ,
99+ generateTemplate ( options , ctx ) ,
100+ [ `return ` ] ,
101+ ) ;
102+ yield `})()${ endOfLine } ` ;
103+ }
104+
105+ // <script> tail
106+ if ( exportDefault ) {
107+ const { expression } = componentOptions ?? exportDefault ;
108+ yield * generateSfcBlockSection ( script , exportDefault . start , expression . start , codeFeatures . all ) ;
109+ yield exportExpression ;
110+ yield * generateSfcBlockSection ( script , expression . end , script . content . length , codeFeatures . all ) ;
111+ }
112+ else {
113+ yield `export default ${ exportExpression } ${ endOfLine } ` ;
114+ }
115+ }
116+ // only <script setup>
117+ else if ( scriptSetup && scriptSetupRanges ) {
118+ if ( scriptSetup . generic ) {
119+ yield * generateExportDeclareEqual ( scriptSetup ) ;
120+ yield * generateGeneric (
121+ options ,
122+ ctx ,
123+ scriptSetup ,
124+ scriptSetupRanges ,
125+ scriptSetup . generic ,
126+ generateSetupFunction (
127+ options ,
128+ ctx ,
129+ scriptSetup ,
130+ scriptSetupRanges ,
131+ generateTemplate ( options , ctx ) ,
132+ ) ,
133+ ) ;
66134 }
67- else if ( exportDefault ) {
135+ else {
136+ // no script block, generate script setup code at root
137+ yield * generateSetupFunction (
138+ options ,
139+ ctx ,
140+ scriptSetup ,
141+ scriptSetupRanges ,
142+ generateTemplate ( options , ctx ) ,
143+ generateExportDeclareEqual ( scriptSetup ) ,
144+ ) ;
145+ }
146+ yield `export default ${ exportExpression } ${ endOfLine } ` ;
147+ }
148+ // only <script>
149+ else if ( script && scriptRanges ) {
150+ const { exportDefault, componentOptions } = scriptRanges ;
151+ if ( exportDefault ) {
68152 const { expression } = componentOptions ?? exportDefault ;
69153
70154 let wrapLeft : string | undefined ;
71155 let wrapRight : string | undefined ;
72156 if (
73- options . script . content [ expression . start ] === '{'
74- && options . vueCompilerOptions . optionsWrapper . length
157+ script . content [ expression . start ] === '{'
158+ && vueCompilerOptions . optionsWrapper . length
75159 ) {
76- [ wrapLeft , wrapRight ] = options . vueCompilerOptions . optionsWrapper ;
160+ [ wrapLeft , wrapRight ] = vueCompilerOptions . optionsWrapper ;
77161 ctx . inlayHints . push ( {
78- blockName : options . script . name ,
162+ blockName : script . name ,
79163 offset : expression . start ,
80164 setting : 'vue.inlayHints.optionsWrapper' ,
81165 label : wrapLeft || '[Missing optionsWrapper[0]]' ,
@@ -84,47 +168,42 @@ function* generateScript(
84168 'To hide it, you can set `"vue.inlayHints.optionsWrapper": false` in IDE settings.' ,
85169 ] . join ( '\n\n' ) ,
86170 } , {
87- blockName : options . script . name ,
171+ blockName : script . name ,
88172 offset : expression . end ,
89173 setting : 'vue.inlayHints.optionsWrapper' ,
90174 label : wrapRight || '[Missing optionsWrapper[1]]' ,
91175 } ) ;
92176 }
93177
94- yield * generateSfcBlockSection ( options . script , 0 , exportDefault . start , codeFeatures . all , true ) ;
95- yield * generateConstExport ( options . script ) ;
178+ yield * generateSfcBlockSection ( script , 0 , exportDefault . start , codeFeatures . all , true ) ;
179+ yield * generateExportDeclareEqual ( script ) ;
96180 if ( wrapLeft ) {
97181 yield wrapLeft ;
98182 }
99- yield * generateSfcBlockSection ( options . script , expression . start , expression . end , codeFeatures . all ) ;
183+ yield * generateSfcBlockSection ( script , expression . start , expression . end , codeFeatures . all ) ;
100184 if ( wrapRight ) {
101185 yield wrapRight ;
102186 }
103187 yield endOfLine ;
188+ yield * generateTemplate ( options , ctx ) ;
189+ yield * generateSfcBlockSection ( script , exportDefault . start , expression . start , codeFeatures . all ) ;
190+ yield exportExpression ;
191+ yield * generateSfcBlockSection ( script , expression . end , script . content . length , codeFeatures . all ) ;
104192 }
105193 else {
106- yield * generateSfcBlockSection ( options . script , 0 , options . script . content . length , codeFeatures . all , true ) ;
107- yield * generateConstExport ( options . script ) ;
108- yield `(await import('${ options . vueCompilerOptions . lib } ')).defineComponent({})${ endOfLine } ` ;
194+ yield * generateSfcBlockSection ( script , 0 , script . content . length , codeFeatures . all , true ) ;
195+ yield * generateExportDeclareEqual ( script ) ;
196+ yield `(await import('${ vueCompilerOptions . lib } ')).defineComponent({})${ endOfLine } ` ;
197+ yield * generateTemplate ( options , ctx ) ;
198+ yield `export default ${ exportExpression } ${ endOfLine } ` ;
109199 }
110200 }
111- else if ( options . scriptSetup && options . scriptSetupRanges ) {
112- yield * generateScriptSetup ( options , ctx , options . scriptSetup , options . scriptSetupRanges ) ;
113- }
114-
115- if ( ! ctx . generatedTemplate ) {
116- yield * generateTemplate ( options , ctx ) ;
117- }
118201
119- yield * generateExportDefault ( options ) ;
120202 yield * ctx . localTypes . generate ( ) ;
121203}
122204
123- function * generateGlobalTypesReference (
124- options : ScriptCodegenOptions ,
125- ) : Generator < Code > {
205+ function * generateGlobalTypesReference ( options : ScriptCodegenOptions ) : Generator < Code > {
126206 const globalTypesPath = options . vueCompilerOptions . globalTypesPath ( options . fileName ) ;
127-
128207 if ( ! globalTypesPath ) {
129208 yield `/* placeholder */${ newLine } ` ;
130209 }
@@ -144,55 +223,10 @@ function* generateGlobalTypesReference(
144223 }
145224}
146225
147- export function * generateConstExport (
148- block : SfcBlock ,
149- ) : Generator < Code > {
226+ function * generateExportDeclareEqual ( block : SfcBlock ) : Generator < Code > {
150227 yield `const ` ;
151228 const token = yield * startBoundary ( block . name , 0 , codeFeatures . doNotReportTs6133 ) ;
152229 yield names . _export ;
153230 yield endBoundary ( token , block . content . length ) ;
154231 yield ` = ` ;
155232}
156-
157- function * generateExportDefault ( options : ScriptCodegenOptions ) : Generator < Code > {
158- if ( options . script ?. src ) {
159- yield * generateSrc ( options . script . src ) ;
160- return ;
161- }
162-
163- const expression = `{} as typeof ${ names . _export } ` ;
164-
165- if ( options . script && options . scriptRanges ?. exportDefault ) {
166- const { exportDefault, componentOptions } = options . scriptRanges ;
167- yield * generateSfcBlockSection (
168- options . script ,
169- exportDefault . start ,
170- ( componentOptions ?? exportDefault ) . expression . start ,
171- codeFeatures . all ,
172- ) ;
173- yield expression ;
174- yield * generateSfcBlockSection (
175- options . script ,
176- ( componentOptions ?? exportDefault ) . expression . end ,
177- options . script . content . length ,
178- codeFeatures . all ,
179- ) ;
180- }
181- else {
182- yield `export ` ;
183- if ( options . templateStartTagOffset !== undefined ) {
184- const token = Symbol ( ) ;
185- for ( let i = 0 ; i < 'template' . length + 1 ; i ++ ) {
186- yield [
187- `` ,
188- 'template' ,
189- options . templateStartTagOffset + 1 + i ,
190- i === 0
191- ? { ...codeFeatures . navigationWithoutRename , __combineToken : token }
192- : { __combineToken : token } ,
193- ] ;
194- }
195- }
196- yield `default ${ expression } ${ endOfLine } ` ;
197- }
198- }
0 commit comments