1
+ import { TransformError } from '@vue-macros/common'
2
+ import { err , ok , safeTry , type ResultAsync } from 'neverthrow'
3
+ import type { ErrorUnknownNode } from '../error'
1
4
import { isTSDeclaration } from './is'
2
5
import { resolveDts } from './resolve-file'
3
6
import {
@@ -20,124 +23,143 @@ export function isTSNamespace(val: unknown): val is TSNamespace {
20
23
*
21
24
* @limitation don't support non-TS declaration (e.g. class, function...)
22
25
*/
23
- export async function resolveTSNamespace ( scope : TSScope ) : Promise < void > {
24
- if ( scope . exports ) return
25
-
26
- const exports : TSNamespace = {
27
- [ namespaceSymbol ] : true ,
28
- }
29
- scope . exports = exports
30
-
31
- const declarations : TSNamespace = {
32
- [ namespaceSymbol ] : true ,
33
- ...scope . declarations ,
34
- }
35
- scope . declarations = declarations
36
-
37
- const { body, file } = resolveTSScope ( scope )
38
- for ( const stmt of body || [ ] ) {
39
- if (
40
- stmt . type === 'ExportDefaultDeclaration' &&
41
- isTSDeclaration ( stmt . declaration )
42
- ) {
43
- exports . default = await resolveTSReferencedType ( {
44
- scope,
45
- type : stmt . declaration ,
46
- } )
47
- } else if ( stmt . type === 'ExportAllDeclaration' ) {
48
- const resolved = await resolveDts ( stmt . source . value , file . filePath )
49
- if ( ! resolved ) continue
50
-
51
- const sourceScope = await getTSFile ( resolved )
52
- await resolveTSNamespace ( sourceScope )
53
-
54
- Object . assign ( exports , sourceScope . exports ! )
55
- } else if ( stmt . type === 'ExportNamedDeclaration' ) {
56
- let sourceExports : TSNamespace
57
-
58
- if ( stmt . source ) {
26
+ export function resolveTSNamespace (
27
+ scope : TSScope ,
28
+ ) : ResultAsync < void , TransformError < ErrorUnknownNode > > {
29
+ return safeTry ( async function * ( ) {
30
+ if ( scope . exports ) return ok ( )
31
+
32
+ const exports : TSNamespace = {
33
+ [ namespaceSymbol ] : true ,
34
+ }
35
+ scope . exports = exports
36
+
37
+ const declarations : TSNamespace = {
38
+ [ namespaceSymbol ] : true ,
39
+ ...scope . declarations ,
40
+ }
41
+ scope . declarations = declarations
42
+
43
+ const { body, file } = resolveTSScope ( scope )
44
+ for ( const stmt of body || [ ] ) {
45
+ if (
46
+ stmt . type === 'ExportDefaultDeclaration' &&
47
+ isTSDeclaration ( stmt . declaration )
48
+ ) {
49
+ exports . default = yield * resolveTSReferencedType ( {
50
+ scope,
51
+ type : stmt . declaration ,
52
+ } )
53
+ } else if ( stmt . type === 'ExportAllDeclaration' ) {
59
54
const resolved = await resolveDts ( stmt . source . value , file . filePath )
60
55
if ( ! resolved ) continue
61
56
62
- const scope = await getTSFile ( resolved )
63
- await resolveTSNamespace ( scope )
64
- sourceExports = scope . exports !
65
- } else {
66
- sourceExports = declarations
67
- }
57
+ const sourceScope = await getTSFile ( resolved )
58
+ yield * resolveTSNamespace ( sourceScope )
59
+
60
+ Object . assign ( exports , sourceScope . exports ! )
61
+ } else if ( stmt . type === 'ExportNamedDeclaration' ) {
62
+ let sourceExports : TSNamespace
68
63
69
- for ( const specifier of stmt . specifiers ) {
70
- let exported : TSNamespace [ string ]
71
- if ( specifier . type === 'ExportDefaultSpecifier' ) {
72
- // export x from 'xxx'
73
- exported = sourceExports . default
74
- } else if ( specifier . type === 'ExportNamespaceSpecifier' ) {
75
- // export * as x from 'xxx'
76
- exported = sourceExports
77
- } else if ( specifier . type === 'ExportSpecifier' ) {
78
- // export { x } from 'xxx'
79
- exported = sourceExports ! [ specifier . local . name ]
64
+ if ( stmt . source ) {
65
+ const resolved = await resolveDts ( stmt . source . value , file . filePath )
66
+ if ( ! resolved ) continue
67
+
68
+ const scope = await getTSFile ( resolved )
69
+ yield * resolveTSNamespace ( scope )
70
+ sourceExports = scope . exports !
80
71
1241
} else {
81
- throw new Error ( `Unknown export type: ${ ( specifier as any ) . type } ` )
72
+ sourceExports = declarations
82
73
}
83
74
84
- const name =
85
- specifier . exported . type === 'Identifier'
86
- ? specifier . exported . name
87
- : specifier . exported . value
88
- exports [ name ] = exported
89
- }
75
+ for ( const specifier of stmt . specifiers ) {
76
+ let exported : TSNamespace [ string ]
77
+ if ( specifier . type === 'ExportDefaultSpecifier' ) {
78
+ // export x from 'xxx'
79
+ exported = sourceExports . default
80
+ } else if ( specifier . type === 'ExportNamespaceSpecifier' ) {
81
+ // export * as x from 'xxx'
82
+ exported = sourceExports
83
+ } else if ( specifier . type === 'ExportSpecifier' ) {
84
+ // export { x } from 'xxx'
85
+ exported = sourceExports ! [ specifier . local . name ]
86
+ } else {
87
+ return err (
88
+ new TransformError (
89
+ `Unknown export type: ${
90
+ // @ts -expect-error unknown type
91
+ specifier . type as string
92
+ } `,
93
+ ) ,
94
+ )
95
+ }
90
96
91
- // export interface A {}
92
- if ( isTSDeclaration ( stmt . declaration ) ) {
93
- const decl = stmt . declaration
94
-
95
- if ( decl . id ?. type === 'Identifier' ) {
96
- const exportedName = decl . id . name
97
- declarations [ exportedName ] = exports [ exportedName ] =
98
- await resolveTSReferencedType ( {
99
- scope,
100
- type : decl ,
101
- } )
97
+ const name =
98
+ specifier . exported . type === 'Identifier'
99
+ ? specifier . exported . name
100
+ : specifier . exported . value
101
+ exports [ name ] = exported
102
+ }
103
+
104
+ // export interface A {}
105
+ if ( isTSDeclaration ( stmt . declaration ) ) {
106
+ const decl = stmt . declaration
107
+
108
+ if ( decl . id ?. type === 'Identifier' ) {
109
+ const exportedName = decl . id . name
110
+ declarations [ exportedName ] = exports [ exportedName ] =
111
+ yield * resolveTSReferencedType ( {
112
+ scope,
113
+ type : decl ,
114
+ } )
115
+ }
102
116
}
103
117
}
104
- }
105
118
106
- // declarations
107
- else if ( isTSDeclaration ( stmt ) ) {
108
- if ( stmt . id ?. type !== 'Identifier' ) continue
109
-
110
- declarations [ stmt . id . name ] = await resolveTSReferencedType ( {
111
- scope,
112
- type : stmt ,
113
- } )
114
- } else if ( stmt . type === 'ImportDeclaration' ) {
115
- const resolved = await resolveDts ( stmt . source . value , file . filePath )
116
- if ( ! resolved ) continue
117
-
118
- const importScope = await getTSFile ( resolved )
119
- await resolveTSNamespace ( importScope )
120
- const exports = importScope . exports !
121
-
122
- for ( const specifier of stmt . specifiers ) {
123
- const local = specifier . local . name
124
-
125
- let imported : TSNamespace [ string ]
126
- if ( specifier . type === 'ImportDefaultSpecifier' ) {
127
- imported = exports . default
128
- } else if ( specifier . type === 'ImportNamespaceSpecifier' ) {
129
- imported = exports
130
- } else if ( specifier . type === 'ImportSpecifier' ) {
131
- const name =
132
- specifier . imported . type === 'Identifier'
133
- ? specifier . imported . name
134
- : specifier . imported . value
135
- imported = exports [ name ]
136
- } else {
137
- throw new Error ( `Unknown import type: ${ ( specifier as any ) . type } ` )
119
+ // declarations
120
+ else if ( isTSDeclaration ( stmt ) ) {
121
+ if ( stmt . id ?. type !== 'Identifier' ) continue
122
+
123
+ declarations [ stmt . id . name ] = yield * resolveTSReferencedType ( {
124
+ scope,
125
+ type : stmt ,
126
+ } )
127
+ } else if ( stmt . type === 'ImportDeclaration' ) {
128
+ const resolved = await resolveDts ( stmt . source . value , file . filePath )
129
+ if ( ! resolved ) continue
130
+
131
+ const importScope = await getTSFile ( resolved )
132
+ yield * resolveTSNamespace ( importScope )
133
+ const exports = importScope . exports !
134
+
135
+ for ( const specifier of stmt . specifiers ) {
136
+ const local = specifier . local . name
137
+
138
+ let imported : TSNamespace [ string ]
139
+ if ( specifier . type === 'ImportDefaultSpecifier' ) {
140
+ imported = exports . default
141
+ } else if ( specifier . type === 'ImportNamespaceSpecifier' ) {
142
+ imported = exports
143
+ } else if ( specifier . type === 'ImportSpecifier' ) {
144
+ const name =
145
+ specifier . imported . type === 'Identifier'
146
+ ? specifier . imported . name
147
+ : specifier . imported . value
148
<
A18B
/td>+ imported = exports [ name ]
149
+ } else {
150
+ return err (
151
+ new TransformError (
152
+ `Unknown import type: ${
153
+ // @ts -expect-error unknown type
154
+ specifier . type as string
155
+ } `,
156
+ ) ,
157
+ )
158
+ }
159
+ declarations [ local ] = imported
138
160
}
139
- declarations [ local ] = imported
140
161
}
141
162
}
142
- }
163
+ return ok ( )
164
+ } )
143
165
}
0 commit comments