77import {
88 Cache ,
99 createCache ,
10+ first ,
11+ invariant ,
1012 rebaseSourceMap ,
1113 SourceTransformer ,
1214} from '@vuedx/shared'
@@ -15,6 +17,7 @@ import type {
1517 TransformOptionsResolved ,
1618} from '../types/TransformOptions'
1719import { transformCustomBlock } from './blocks/transformCustomBlock'
20+ import { createProgram } from '@vuedx/transforms'
1821
1922import type { RootNode } from '@vue/compiler-core'
2023import type { RawSourceMap } from 'source-map'
@@ -219,64 +222,61 @@ export function compileWithDecodedSourceMap(
219222 } )
220223
221224 const exported = [
222- scriptSetup . exportIdentifier ,
223- scriptSetup . propsIdentifier ,
224- scriptSetup . emitsIdentifier ,
225- scriptSetup . exposeIdentifier ,
226- template . attrsIdentifier ,
227- template . slotsIdentifier ,
228- resolvedOptions . contextIdentifier ,
225+ ...( descriptor . scriptSetup == null
226+ ? [ template . attrsIdentifier , template . slotsIdentifier , contextIdentifier ]
227+ : [ scriptSetup . componentIdentifier ] ) ,
229228 ...Object . values ( scriptSetup . exports ) ,
230229 ] . join ( ', ' )
231230
232- builder . append ( `return {${ exported } };}) ;` )
231+ builder . append ( `return {${ exported } };};` )
233232 builder . nextLine ( )
234- builder . append ( `const {${ exported } } = ${ scriptSetup . scopeIdentifier } ;\n` )
233+ builder . append ( `const {${ exported } } = ${ scriptSetup . scopeIdentifier } () ;\n` )
235234 Object . entries ( scriptSetup . exports ) . forEach ( ( [ name , identifier ] ) => {
236235 builder . append ( `export type ${ name } = typeof ${ identifier } ;\n` )
237236 } )
238237
239238 region ( 'public component definition' , ( ) => {
240- const props = `${ resolvedOptions . contextIdentifier } .$props`
241-
242- const parentClassIfAny = ` extends ${ name } Public`
243- const type = `new () => typeof ${ scriptSetup . exposeIdentifier } `
244- if ( resolvedOptions . isTypeScript ) {
245- builder . append ( `const ${ name } Public = null as unknown as ${ type } ;` )
246- builder . nextLine ( )
239+ if ( descriptor . scriptSetup == null ) {
240+ const props = `${ resolvedOptions . contextIdentifier } .$props`
241+ const inheritAttrs =
242+ descriptor . template ?. content . includes ( '@vue-attrs-target' ) === true ||
243+ script . inheritAttrs
244+ const propsType = `typeof ${ props } `
245+ const attrsType = `typeof ${ template . attrsIdentifier } `
246+ const slotsType = `${ resolvedOptions . typeIdentifier } .internal.Slots<ReturnType<typeof ${ template . slotsIdentifier } >>`
247+ builder . append (
248+ [
249+ `export default class ${ name } {` ,
250+ defineProperty (
251+ '$props' ,
252+ inheritAttrs
253+ ? `${ resolvedOptions . typeIdentifier } .internal.MergeAttrs<${ propsType } , ${ attrsType } > & {$slots: ${ slotsType } }`
254+ : `${ propsType } & {$slots: ${ slotsType } }` ,
255+ ) ,
256+ `}` ,
257+ ] . join ( '\n' ) ,
258+ )
247259 } else {
260+ const generic =
261+ typeof descriptor . scriptSetup . attrs [ 'generic' ] === 'string'
262+ ? descriptor . scriptSetup . attrs [ 'generic' ]
263+ : ''
264+ const typeArgs = parseGenericArgNames ( generic )
265+
266+ const component =
267+ typeArgs . length > 0
268+ ? `(new (${ scriptSetup . scopeIdentifier } <${ typeArgs . join ( ', ' ) } >().${
269+ scriptSetup . componentIdentifier
270+ } <${ typeArgs . join ( ', ' ) } >))`
271+ : `(new (${ scriptSetup . scopeIdentifier } ().${ scriptSetup . componentIdentifier } ))`
272+
273+ const genericExp = typeArgs . length > 0 ? `<${ generic } >` : ''
274+ builder . append ( `export default class ${ name } ${ genericExp } {\n` )
248275 builder . append (
249- `const ${ name } Public = /** @type { ${ type } } */ (/** @type {unknown} */ (null)); ` ,
276+ ` $props = {... ${ component } .$props, $slots: ${ component } .$slots };\n ` ,
250277 )
251- builder . nextLine ( )
278+ builder . append ( `}` )
252279 }
253-
254- const inheritAttrs =
255- descriptor . template ?. content . includes ( '@vue-attrs-target' ) === true ||
256- script . inheritAttrs
257-
258- const propsType =
259- descriptor . scriptSetup != null
260- ? `typeof ${ props } & ${ resolvedOptions . typeIdentifier } .internal.EmitsToProps<typeof ${ scriptSetup . emitsIdentifier } >`
261- : `typeof ${ props } `
262- const attrsType = `typeof ${ template . attrsIdentifier } `
263-
264- builder . append (
265- [
266- `export default class ${ name } ${ parentClassIfAny } {` ,
267- defineProperty (
268- '$props' ,
269- inheritAttrs
270- ? `${ resolvedOptions . typeIdentifier } .internal.MergeAttrs<${ propsType } , ${ attrsType } >`
271- : propsType ,
272- ) ,
273- defineProperty (
274- '$slots' ,
275- `${ resolvedOptions . typeIdentifier } .internal.Slots<ReturnType<typeof ${ template . slotsIdentifier } >>` ,
276- ) ,
277- `}` ,
278- ] . join ( '\n' ) ,
279- )
280280 builder . nextLine ( )
281281 } )
282282
@@ -303,6 +303,17 @@ export function compileWithDecodedSourceMap(
303303 ? ` ${ name } = null as unknown as ${ type } ;`
304304 : ` ${ name } = /** @type {${ type } } */ (/** @type {unknown} */ (null));`
305305 }
306+
307+ function parseGenericArgNames ( code : string ) : string [ ] {
308+ const ts = options . typescript
309+ const program = createProgram ( ts , `function _<${ code } >() {}` )
310+ const sourceFile = program . getSourceFile ( 'input.ts' )
311+ invariant ( sourceFile != null , 'sourceFile should not be null' )
312+ const decl = first ( sourceFile . statements )
313+ invariant ( ts . isFunctionDeclaration ( decl ) )
314+ invariant ( decl . typeParameters != null )
315+ return decl . typeParameters . map ( ( p ) => p . name . getText ( ) )
316+ }
306317}
307318
308319function runIfNeeded < R > (
0 commit comments