@@ -205,3 +205,269 @@ export async function updateResourceConfig(resourceId, columnName, fieldType, co
205205 throw new Error ( `Failed to update resource file ${ path . basename ( filePath ) } : ${ error . message } ` ) ;
206206 }
207207}
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