@@ -25,6 +25,63 @@ interface FileDetails {
25
25
relativeTargetDistDir : string ;
26
26
exportKey : string ;
27
27
}
28
+ const API_DIR = 'api' ;
29
+ const PLUGIN_DIR = 'plugin' ;
30
+ const RUNTIME_DIR = 'runtime' ;
31
+ const CLIENT_DIR = 'client' ;
32
+
33
+ const EXPORT_PREFIX = `./${ API_DIR } /` ;
34
+ const TYPE_PREFIX = `${ API_DIR } /` ;
35
+
36
+ function deepMerge < T extends Record < string , any > > (
37
+ target : T | undefined ,
38
+ source : Partial < T > ,
39
+ strategy ?: {
40
+ array ?: 'append' | 'prepend' | 'replace' ;
41
+ dedupe ?: boolean ;
42
+ } ,
43
+ ) : T {
44
+ const base = ( target || { } ) as T ;
45
+ const merged = { ...base } ;
46
+
47
+ for ( const [ key , value ] of Object . entries ( source ) ) {
48
+ if ( Array . isArray ( value ) && Array . isArray ( base [ key ] ) ) {
49
+ merged [ key as keyof T ] = [
50
+ ...( strategy ?. array === 'prepend' ? value : base [ key ] ) ,
51
+ ...( strategy ?. array === 'append' ? value : [ ] ) ,
52
+ ...( strategy ?. array !== 'replace' && strategy ?. array !== 'prepend'
53
+ ? base [ key ]
54
+ : [ ] ) ,
55
+ ] . filter ( ( v , i , a ) =>
56
+ strategy ?. dedupe
57
+ ? a . findIndex ( e => JSON . stringify ( e ) === JSON . stringify ( v ) ) === i
58
+ : true ,
59
+ ) as T [ keyof T ] ;
60
+ continue ;
61
+ }
62
+
63
+ if ( typeof value === 'object' && value !== null && ! Array . isArray ( value ) ) {
64
+ merged [ key as keyof T ] = deepMerge ( base [ key ] , value , strategy ) ;
65
+ continue ;
66
+ }
67
+
68
+ if ( ! ( key in base ) ) {
69
+ merged [ key as keyof T ] = value ;
70
+ }
71
+ }
72
+
73
+ return merged ;
74
+ }
75
+
76
+ const filterObjectKeys = < T extends Record < string , any > > (
77
+ obj : T | undefined ,
78
+ predicate : ( key : string ) => boolean ,
79
+ ) : T => {
80
+ return Object . fromEntries (
81
+ Object . entries ( obj || { } ) . filter ( ( [ key ] ) => predicate ( key ) ) ,
82
+ ) as T ;
83
+ } ;
84
+
28
85
export async function readDirectoryFiles (
29
86
appDirectory : string ,
30
87
directory : string ,
@@ -48,7 +105,7 @@ export async function readDirectoryFiles(
48
105
const parsedPath = path . parse ( relativePath ) ;
49
106
50
107
const targetDir = path . join (
51
- `./${ relativeDistPath } /client ` ,
108
+ `./${ relativeDistPath } /${ CLIENT_DIR } ` ,
52
109
parsedPath . dir ,
53
110
`${ parsedPath . name } .js` ,
54
111
) ;
@@ -96,61 +153,90 @@ async function setPackage(
96
153
} [ ] ,
97
154
appDirectory : string ,
98
155
relativeDistPath : string ,
99
- relativeApiPath : string ,
100
156
) {
101
157
try {
102
158
const packagePath = path . resolve ( appDirectory , './package.json' ) ;
103
159
const packageContent = await fs . readFile ( packagePath , 'utf8' ) ;
104
160
const packageJson = JSON . parse ( packageContent ) ;
105
161
106
- packageJson . exports = packageJson . exports || { } ;
107
- packageJson . typesVersions = packageJson . typesVersions || { '*' : { } } ;
108
-
109
- files . forEach ( file => {
110
- const exportKey = `./api/${ file . exportKey } ` ;
111
- const jsFilePath = `./${ file . targetDir } ` ;
112
- const typePath = file . relativeTargetDistDir ;
113
-
114
- packageJson . exports [ exportKey ] = {
115
- import : jsFilePath ,
116
- types : typePath ,
117
- } ;
118
-
119
- packageJson . typesVersions [ '*' ] [ `api/${ file . exportKey } ` ] = [ typePath ] ;
120
- } ) ;
162
+ packageJson . exports = filterObjectKeys (
163
+ packageJson . exports ,
164
+ key => ! key . startsWith ( EXPORT_PREFIX ) ,
165
+ ) ;
121
166
122
- packageJson . exports [ './plugin' ] = {
123
- require : `./${ relativeDistPath } /plugin/index.js` ,
124
- types : `./${ relativeDistPath } /plugin/index.d.ts` ,
125
- } ;
167
+ if ( packageJson . typesVersions ?. [ '*' ] ) {
168
+ packageJson . typesVersions [ '*' ] = filterObjectKeys (
169
+ packageJson . typesVersions [ '*' ] ,
170
+ key => ! key . startsWith ( TYPE_PREFIX ) ,
171
+ ) ;
172
+ }
126
173
127
- packageJson . exports [ './runtime' ] = {
128
- import : `./${ relativeDistPath } /runtime/index.js` ,
129
- types : `./${ relativeDistPath } /runtime/index.d.ts` ,
130
- } ;
131
- packageJson . typesVersions [ '*' ] . runtime = [
132
- `./${ relativeDistPath } /runtime/index.d.ts` ,
133
- ] ;
134
- packageJson . typesVersions [ '*' ] . plugin = [
135
- `./${ relativeDistPath } /plugin/index.d.ts` ,
136
- ] ;
137
-
138
- packageJson . files = [
139
- `${ relativeDistPath } /client/**/*` ,
140
- `${ relativeDistPath } /${ relativeApiPath } /**/*` ,
141
- `${ relativeDistPath } /runtime/**/*` ,
142
- `${ relativeDistPath } /plugin/**/*` ,
143
- ] ;
174
+ const mergedPackage = deepMerge (
175
+ packageJson ,
176
+ {
177
+ exports : files . reduce (
178
+ ( acc , file ) => {
179
+ const exportKey = `${ EXPORT_PREFIX } ${ file . exportKey } ` ;
180
+ const jsFilePath = `./${ file . targetDir } ` ;
181
+ return deepMerge ( acc , {
182
+ [ exportKey ] : {
183
+ import : jsFilePath ,
184
+ types : jsFilePath . replace ( 'js' , 'd.ts' ) ,
185
+ } ,
186
+ } ) ;
187
+ } ,
188
+ {
189
+ './plugin' : {
190
+ require : `./${ relativeDistPath } /${ PLUGIN_DIR } /index.js` ,
191
+ types : `./${ relativeDistPath } /${ PLUGIN_DIR } /index.d.ts` ,
192
+ } ,
193
+ './runtime' : {
194
+ import : `./${ relativeDistPath } /${ RUNTIME_DIR } /index.js` ,
195
+ types : `./${ relativeDistPath } /${ RUNTIME_DIR } /index.d.ts` ,
196
+ } ,
197
+ } ,
198
+ ) ,
199
+ typesVersions : {
200
+ '*' : files . reduce (
201
+ ( acc , file ) =>
202
+ deepMerge ( acc , {
203
+ [ `${ TYPE_PREFIX } ${ file . exportKey } ` ] : [
204
+ file . relativeTargetDistDir ,
205
+ ] ,
206
+ } ) ,
207
+ {
208
+ runtime : [ `./${ relativeDistPath } /${ RUNTIME_DIR } /index.d.ts` ] ,
209
+ plugin : [ `./${ relativeDistPath } /${ PLUGIN_DIR } /index.d.ts` ] ,
210
+ } ,
211
+ ) ,
212
+ } ,
213
+ files : [
214
+ `${ relativeDistPath } /${ CLIENT_DIR } /**/*` ,
215
+ `${ relativeDistPath } /${ RUNTIME_DIR } /**/*` ,
216
+ `${ relativeDistPath } /${ PLUGIN_DIR } /**/*` ,
217
+ ] ,
218
+ } ,
219
+ {
220
+ array : 'append' ,
221
+ dedupe : true ,
222
+ } ,
223
+ ) ;
144
224
145
225
await fs . promises . writeFile (
146
226
packagePath ,
147
- JSON . stringify ( packageJson , null , 2 ) ,
227
+ JSON . stringify ( mergedPackage , null , 2 ) ,
148
228
) ;
149
229
} catch ( error ) {
150
230
logger . error ( `package.json update failed: ${ error } ` ) ;
151
231
}
152
232
}
153
233
234
+ export async function copyFiles ( from : string , to : string ) {
235
+ if ( await fs . pathExists ( from ) ) {
236
+ await fs . copy ( from , to ) ;
237
+ }
238
+ }
239
+
154
240
async function clientGenerator ( draftOptions : APILoaderOptions ) {
155
241
const sourceList = await readDirectoryFiles (
156
242
draftOptions . appDir ,
@@ -197,19 +283,18 @@ async function clientGenerator(draftOptions: APILoaderOptions) {
197
283
const code = await getClitentCode ( source . resourcePath , source . source ) ;
198
284
if ( code ?. value ) {
199
285
await writeTargetFile ( source . absTargetDir , code . value ) ;
286
+ await copyFiles (
287
+ source . relativeTargetDistDir ,
288
+ source . targetDir . replace ( `js` , 'd.ts' ) ,
289
+ ) ;
200
290
}
201
291
}
202
292
logger . info ( `Client bundle generate succeed` ) ;
203
293
} catch ( error ) {
204
294
logger . error ( `Client bundle generate failed: ${ error } ` ) ;
205
295
}
206
296
207
- setPackage (
208
- sourceList ,
209
- draftOptions . appDir ,
210
- draftOptions . relativeDistPath ,
211
- draftOptions . relativeApiPath ,
212
- ) ;
297
+ setPackage ( sourceList , draftOptions . appDir , draftOptions . relativeDistPath ) ;
213
298
}
214
299
215
300
export default clientGenerator ;
0 commit comments