@@ -205,3 +205,269 @@ export async function updateResourceConfig(resourceId, columnName, fieldType, co
205
205
throw new Error ( `Failed to update resource file ${ path . basename ( filePath ) } : ${ error . message } ` ) ;
206
206
}
207
207
}
208
+
209
+
210
+ export async function injectLoginComponent ( indexFilePath , componentPath ) {
211
+ console . log ( chalk . dim ( `Reading file: ${ indexFilePath } ` ) ) ;
212
+ const content = await fs . readFile ( indexFilePath , 'utf-8' ) ;
213
+ const ast = recast . parse ( content , {
214
+ parser : typescriptParser ,
215
+ } ) ;
216
+
217
+ let updated = false ;
218
+
219
+ recast . visit ( ast , {
220
+ visitNewExpression ( path ) {
221
+ if (
222
+ n . Identifier . check ( path . node . callee ) &&
223
+ path . node . callee . name === 'AdminForth' &&
224
+ path . node . arguments . length > 0 &&
225
+ n . ObjectExpression . check ( path . node . arguments [ 0 ] )
226
+ ) {
227
+ const configObject = path . node . arguments [ 0 ] ;
228
+
229
+ let customizationProp = configObject . properties . find (
230
+ p => n . ObjectProperty . check ( p ) && n . Identifier . check ( p . key ) && p . key . name === 'customization'
231
+ ) ;
232
+
233
+ if ( ! customizationProp ) {
234
+ // Добавляем customization: {}
235
+ const customizationObj = b . objectExpression ( [ ] ) ;
236
+ customizationProp = b . objectProperty ( b . identifier ( 'customization' ) , customizationObj ) ;
237
+ configObject . properties . push ( customizationProp ) ;
238
+ console . log ( chalk . dim ( `Added missing 'customization' property.` ) ) ;
239
+ }
240
+
241
+ const customizationValue = customizationProp . value ;
242
+ if ( ! n . ObjectExpression . check ( customizationValue ) ) return false ;
243
+
244
+ let loginPageInjections = customizationValue . properties . find (
245
+ p => n . ObjectProperty . check ( p ) && n . Identifier . check ( p . key ) && p . key . name === 'loginPageInjections'
246
+ ) ;
247
+
248
+ if ( ! loginPageInjections ) {
249
+ const injectionsObj = b . objectExpression ( [ ] ) ;
250
+ loginPageInjections = b . objectProperty ( b . identifier ( 'loginPageInjections' ) , injectionsObj ) ;
251
+ customizationValue . properties . push ( loginPageInjections ) ;
252
+ console . log ( chalk . dim ( `Added missing 'loginPageInjections'.` ) ) ;
253
+ }
254
+
255
+ const injectionsValue = loginPageInjections . value ;
256
+ if ( ! n . ObjectExpression . check ( injectionsValue ) ) return false ;
257
+
258
+ let underInputsProp = injectionsValue . properties . find (
259
+ p => n . ObjectProperty . check ( p ) && n . Identifier . check ( p . key ) && p . key . name === 'underInputs'
260
+ ) ;
261
+
262
+ if ( underInputsProp ) {
263
+ underInputsProp . value = b . stringLiteral ( componentPath ) ;
264
+ console . log ( chalk . dim ( `Updated 'underInputs' to ${ componentPath } ` ) ) ;
265
+ } else {
266
+ injectionsValue . properties . push (
267
+ b . objectProperty ( b . identifier ( 'underInputs' ) , b . stringLiteral ( componentPath ) )
268
+ ) ;
269
+ console . log ( chalk . dim ( `Added 'underInputs': ${ componentPath } ` ) ) ;
270
+ }
271
+
272
+ updated = true ;
273
+ this . abort ( ) ;
274
+ }
275
+ return false ;
276
+ }
277
+ } ) ;
278
+
279
+ if ( ! updated ) {
280
+ throw new Error ( `Could not find AdminForth configuration in file: ${ indexFilePath } ` ) ;
281
+ }
282
+
283
+ const outputCode = recast . print ( ast ) . code ;
284
+ await fs . writeFile ( indexFilePath , outputCode , 'utf-8' ) ;
285
+ console . log ( chalk . green ( `✅ Successfully updated login injection in: ${ indexFilePath } ` ) ) ;
286
+ }
287
+
288
+
289
+ export async function injectGlobalComponent ( indexFilePath , injectionType , componentPath ) {
290
+ console . log ( chalk . dim ( `Reading file: ${ indexFilePath } ` ) ) ;
291
+ const content = await fs . readFile ( indexFilePath , 'utf-8' ) ;
292
+ const ast = recast . parse ( content , {
293
+ parser : typescriptParser ,
294
+ } ) ;
295
+
296
+ let updated = false ;
297
+
298
+ recast . visit ( ast , {
299
+ visitNewExpression ( path ) {
300
+ if (
301
+ n . Identifier . check ( path . node . callee ) &&
302
+ path . node . callee . name === 'AdminForth' &&
303
+ path . node . arguments . length > 0 &&
304
+ n . ObjectExpression . check ( path . node . arguments [ 0 ] )
305
+ ) {
306
+ const configObject = path . node . arguments [ 0 ] ;
307
+
308
+ let customizationProp = configObject . properties . find (
309
+ p => n . ObjectProperty . check ( p ) && n . Identifier . check ( p . key ) && p . key . name === 'customization'
310
+ ) ;
311
+
312
+ if ( ! customizationProp ) {
313
+ const customizationObj = b . objectExpression ( [ ] ) ;
314
+ customizationProp = b . objectProperty ( b . identifier ( 'customization' ) , customizationObj ) ;
315
+ configObject . properties . push ( customizationProp ) ;
316
+ console . log ( chalk . dim ( `Added missing 'customization' property.` ) ) ;
317
+ }
318
+
319
+ const customizationValue = customizationProp . value ;
320
+ if ( ! n . ObjectExpression . check ( customizationValue ) ) return false ;
321
+
322
+ let globalInjections = customizationValue . properties . find (
323
+ p => n . ObjectProperty . check ( p ) && n . Identifier . check ( p . key ) && p . key . name === 'globalInjections'
324
+ ) ;
325
+
326
+ if ( ! globalInjections ) {
327
+ const injectionsObj = b . objectExpression ( [ ] ) ;
328
+ globalInjections = b . objectProperty ( b . identifier ( 'globalInjections' ) , injectionsObj ) ;
329
+ customizationValue . properties . push ( globalInjections ) ;
330
+ console . log ( chalk . dim ( `Added missing 'globalInjections'.` ) ) ;
331
+ }
332
+
333
+ const injectionsValue = globalInjections . value ;
334
+ if ( ! n . ObjectExpression . check ( injectionsValue ) ) return false ;
335
+
336
+ let injectionProp = injectionsValue . properties . find (
337
+ p => n . ObjectProperty . check ( p ) && n . Identifier . check ( p . key ) && p . key . name === injectionType
338
+ ) ;
339
+
340
+ if ( injectionProp ) {
341
+ const injectionArray = injectionProp . value . elements ;
342
+ injectionArray . push ( b . stringLiteral ( componentPath ) ) ;
343
+ console . log ( chalk . dim ( `Added '${ componentPath } ' to '${ injectionType } '` ) ) ;
344
+ } else {
345
+ injectionsValue . properties . push (
346
+ b . objectProperty ( b . identifier ( injectionType ) , b . arrayExpression ( [ b . stringLiteral ( componentPath ) ] ) )
347
+ ) ;
348
+ console . log ( chalk . dim ( `Added '${ injectionType } ': [${ componentPath } ]` ) ) ;
349
+ }
350
+
351
+ updated = true ;
352
+ this . abort ( ) ;
353
+ }
354
+ return false ;
355
+ }
356
+ } ) ;
357
+
358
+ if ( ! updated ) {
359
+ throw new Error ( `Could not find AdminForth configuration in file: ${ indexFilePath } ` ) ;
360
+ }
361
+
362
+ const outputCode = recast . print ( ast ) . code ;
363
+ await fs . writeFile ( indexFilePath , outputCode , 'utf-8' ) ;
364
+ console . log ( chalk . green ( `✅ Successfully updated global injection '${ injectionType } ' in: ${ indexFilePath } ` ) ) ;
365
+ }
366
+
367
+ export async function updateCrudInjectionConfig ( resourceId , crudType , injectionPosition , componentPathForConfig , isThin ) {
368
+ const filePath = await findResourceFilePath ( resourceId ) ;
369
+ console . log ( chalk . dim ( `Attempting to update resource CRUD injection: ${ filePath } ` ) ) ;
370
+
371
+ let content ;
372
+ try {
373
+ content = await fs . readFile ( filePath , 'utf-8' ) ;
374
+ } catch ( error ) {
375
+ console . error ( chalk . red ( `❌ Error reading resource file: ${ filePath } ` ) ) ;
376
+ throw new Error ( `Could not read resource file ${ filePath } .` ) ;
377
+ }
378
+
379
+ try {
380
+ const ast = recast . parse ( content , {
381
+ parser : typescriptParser
382
+ } ) ;
383
+
384
+ let updateApplied = false ;
385
+
386
+ recast . visit ( ast , {
387
+ visitExportDefaultDeclaration ( path ) {
388
+ const declaration = path . node . declaration ;
389
+ let objectExpressionNode = null ;
390
+
391
+ if ( n . TSAsExpression . check ( declaration ) && n . ObjectExpression . check ( declaration . expression ) ) {
392
+ objectExpressionNode = declaration . expression ;
393
+ } else if ( n . ObjectExpression . check ( declaration ) ) {
394
+ objectExpressionNode = declaration ;
395
+ }
396
+
397
+ if ( ! objectExpressionNode ) {
398
+ console . warn ( chalk . yellow ( `Warning: Default export in ${ filePath } is not an ObjectExpression. Skipping update.` ) ) ;
399
+ return false ;
400
+ }
401
+
402
+ const getOrCreateObjectProp = ( obj , propName ) => {
403
+ let prop = obj . properties . find ( p => n . ObjectProperty . check ( p ) && n . Identifier . check ( p . key ) && p . key . name === propName ) ;
404
+ if ( ! prop ) {
405
+ const newObject = b . objectExpression ( [ ] ) ;
406
+ prop = b . objectProperty ( b . identifier ( propName ) , newObject ) ;
407
+ obj . properties . push ( prop ) ;
408
+ }
409
+ return prop . value ;
410
+ } ;
411
+
412
+ const options = getOrCreateObjectProp ( objectExpressionNode , 'options' ) ;
413
+ if ( ! n . ObjectExpression . check ( options ) ) return false ;
414
+
415
+ const pageInjections = getOrCreateObjectProp ( options , 'pageInjections' ) ;
416
+ if ( ! n . ObjectExpression . check ( pageInjections ) ) return false ;
417
+
418
+ let crudProp = pageInjections . properties . find ( p =>
419
+ n . ObjectProperty . check ( p ) && n . Identifier . check ( p . key ) && p . key . name === crudType
420
+ ) ;
421
+
422
+ if ( ! crudProp ) {
423
+ crudProp = b . objectProperty (
424
+ b . identifier ( crudType ) ,
425
+ b . objectExpression ( [ ] )
426
+ ) ;
427
+ pageInjections . properties . push ( crudProp ) ;
428
+ }
429
+
430
+ const crudValue = crudProp . value ;
431
+ if ( ! n . ObjectExpression . check ( crudValue ) ) return false ;
432
+
433
+ let injectionProp = crudValue . properties . find ( p =>
434
+ n . ObjectProperty . check ( p ) && n . Identifier . check ( p . key ) && p . key . name === injectionPosition
435
+ ) ;
436
+
437
+ const newInjectionObject = b . objectExpression ( [
438
+ b . objectProperty ( b . identifier ( 'file' ) , b . stringLiteral ( componentPathForConfig ) ) ,
439
+ b . objectProperty (
440
+ b . identifier ( 'meta' ) ,
441
+ b . objectExpression ( [
442
+ b . objectProperty ( b . identifier ( 'thinEnoughToShrinkTable' ) , b . booleanLiteral ( ! ! isThin ) ) ,
443
+ ] )
444
+ ) ,
445
+ ] ) ;
446
+
447
+ if ( injectionProp ) {
448
+ injectionProp . value = newInjectionObject ;
449
+ console . log ( chalk . dim ( `Updated '${ injectionPosition } ' injection for '${ crudType } '.` ) ) ;
450
+ } else {
451
+ crudValue . properties . push ( b . objectProperty ( b . identifier ( injectionPosition ) , newInjectionObject ) ) ;
452
+ console . log ( chalk . dim ( `Added '${ injectionPosition } ' injection for '${ crudType } '.` ) ) ;
453
+ }
454
+
455
+ updateApplied = true ;
456
+ this . abort ( ) ;
457
+ return false ;
458
+ }
459
+ } ) ;
460
+
461
+ if ( ! updateApplied ) {
462
+ throw new Error ( `Could not inject CRUD component in resource ${ resourceId } .` ) ;
463
+ }
464
+
465
+ const outputCode = recast . print ( ast ) . code ;
466
+ await fs . writeFile ( filePath , outputCode , 'utf-8' ) ;
467
+ console . log ( chalk . dim ( `✅ Successfully updated CRUD injection in resource file: ${ filePath } ` ) ) ;
468
+
469
+ } catch ( error ) {
470
+ console . error ( chalk . red ( `❌ Error processing resource file: ${ filePath } ` ) ) ;
471
+ throw new Error ( `Failed to inject CRUD component in ${ path . basename ( filePath ) } : ${ error . message } ` ) ;
472
+ }
473
+ }
0 commit comments