@@ -13,54 +13,157 @@ namespace InertiaCore;
1313public class Response : IActionResult
1414{
1515 private readonly string _component ;
16- private readonly object _props ;
16+ private readonly Dictionary < string , object ? > _props ;
1717 private readonly string _rootView ;
1818 private readonly string ? _version ;
1919
2020 private ActionContext ? _context ;
2121 private Page ? _page ;
2222 private IDictionary < string , object > ? _viewData ;
2323
24- public Response ( string component , object props , string rootView , string ? version )
24+ internal Response ( string component , Dictionary < string , object ? > props , string rootView , string ? version )
2525 => ( _component , _props , _rootView , _version ) = ( component , props , rootView , version ) ;
2626
2727 public async Task ExecuteResultAsync ( ActionContext context )
2828 {
2929 SetContext ( context ) ;
3030 await ProcessResponse ( ) ;
31-
3231 await GetResult ( ) . ExecuteResultAsync ( _context ! ) ;
3332 }
3433
3534 protected internal async Task ProcessResponse ( )
3635 {
36+ var props = await ResolveProperties ( ) ;
37+
3738 var page = new Page
3839 {
3940 Component = _component ,
4041 Version = _version ,
4142 Url = _context ! . RequestedUri ( ) ,
42- Props = await ResolveProperties ( _props . GetType ( ) . GetProperties ( )
43- . ToDictionary ( o => o . Name . ToCamelCase ( ) , o => o . GetValue ( _props ) ) )
43+ Props = props
4444 } ;
4545
46- var shared = _context ! . HttpContext . Features . Get < InertiaSharedData > ( ) ;
47- if ( shared != null )
48- page . Props = shared . GetMerged ( page . Props ) ;
49-
5046 page . Props [ "errors" ] = GetErrors ( ) ;
5147
5248 SetPage ( page ) ;
5349 }
5450
55- private static async Task < Dictionary < string , object ? > > PrepareProps ( Dictionary < string , object ? > props )
51+ /// <summary>
52+ /// Resolve the properties for the response.
53+ /// </summary>
54+ private async Task < Dictionary < string , object ? > > ResolveProperties ( )
55+ {
56+ var props = _props ;
57+
58+ props = ResolveSharedProps ( props ) ;
59+ props = ResolvePartialProperties ( props ) ;
60+ props = ResolveAlways ( props ) ;
61+ props = await ResolvePropertyInstances ( props ) ;
62+
63+ return props ;
64+ }
65+
66+ /// <summary>
67+ /// Resolve `shared` props stored in the current request context.
68+ /// </summary>
69+ private Dictionary < string , object ? > ResolveSharedProps ( Dictionary < string , object ? > props )
70+ {
71+ var shared = _context ! . HttpContext . Features . Get < InertiaSharedProps > ( ) ;
72+ if ( shared != null )
73+ props = shared . GetMerged ( props ) ;
74+
75+ return props ;
76+ }
77+
78+ /// <summary>
79+ /// Resolve the `only` and `except` partial request props.
80+ /// </summary>
81+ private Dictionary < string , object ? > ResolvePartialProperties ( Dictionary < string , object ? > props )
82+ {
83+ var isPartial = _context ! . IsInertiaPartialComponent ( _component ) ;
84+
85+ if ( ! isPartial )
86+ return props
87+ . Where ( kv => kv . Value is not LazyProp )
88+ . ToDictionary ( kv => kv . Key , kv => kv . Value ) ;
89+
90+ props = props . ToDictionary ( kv => kv . Key , kv => kv . Value ) ;
91+
92+ if ( _context ! . HttpContext . Request . Headers . ContainsKey ( InertiaHeader . PartialOnly ) )
93+ props = ResolveOnly ( props ) ;
94+
95+ if ( _context ! . HttpContext . Request . Headers . ContainsKey ( InertiaHeader . PartialExcept ) )
96+ props = ResolveExcept ( props ) ;
97+
98+ return props ;
99+ }
100+
101+ /// <summary>
102+ /// Resolve the `only` partial request props.
103+ /// </summary>
104+ private Dictionary < string , object ? > ResolveOnly ( Dictionary < string , object ? > props )
105+ {
106+ var onlyKeys = _context ! . HttpContext . Request . Headers [ InertiaHeader . PartialOnly ]
107+ . ToString ( ) . Split ( ',' )
108+ . Select ( k => k . Trim ( ) )
109+ . Where ( k => ! string . IsNullOrEmpty ( k ) )
110+ . ToList ( ) ;
111+
112+ return props . Where ( kv => onlyKeys . Contains ( kv . Key , StringComparer . OrdinalIgnoreCase ) )
113+ . ToDictionary ( kv => kv . Key , kv => kv . Value ) ;
114+ }
115+
116+ /// <summary>
117+ /// Resolve the `except` partial request props.
118+ /// </summary>
119+ private Dictionary < string , object ? > ResolveExcept ( Dictionary < string , object ? > props )
120+ {
121+ var exceptKeys = _context ! . HttpContext . Request . Headers [ InertiaHeader . PartialExcept ]
122+ . ToString ( ) . Split ( ',' )
123+ . Select ( k => k . Trim ( ) )
124+ . Where ( k => ! string . IsNullOrEmpty ( k ) )
125+ . ToList ( ) ;
126+
127+ return props . Where ( kv => exceptKeys . Contains ( kv . Key , StringComparer . OrdinalIgnoreCase ) == false )
128+ . ToDictionary ( kv => kv . Key , kv => kv . Value ) ;
129+ }
130+
131+ /// <summary>
132+ /// Resolve `always` properties that should always be included on all visits, regardless of "only" or "except" requests.
133+ /// </summary>
134+ private Dictionary < string , object ? > ResolveAlways ( Dictionary < string , object ? > props )
135+ {
136+ var alwaysProps = _props . Where ( o => o . Value is AlwaysProp ) ;
137+
138+ return props
139+ . Where ( kv => kv . Value is not AlwaysProp )
140+ . Concat ( alwaysProps ) . ToDictionary ( kv => kv . Key , kv => kv . Value ) ;
141+ }
142+
143+ /// <summary>
144+ /// Resolve all necessary class instances in the given props.
145+ /// </summary>
146+ private static async Task < Dictionary < string , object ? > > ResolvePropertyInstances ( Dictionary < string , object ? > props )
56147 {
57- return ( await Task . WhenAll ( props . Select ( async pair => pair . Value switch
148+ return ( await Task . WhenAll ( props . Select ( async pair =>
58149 {
59- Func < object ? > f => ( pair . Key , f . Invoke ( ) ) ,
60- LazyProp l => ( pair . Key , await l . Invoke ( ) ) ,
61- AlwaysProp l => ( pair . Key , await l . Invoke ( ) ) ,
62- _ => ( pair . Key , pair . Value )
63- } ) ) ) . ToDictionary ( pair => pair . Key , pair => pair . Item2 ) ;
150+ var key = pair . Key . ToCamelCase ( ) ;
151+
152+ var value = pair . Value switch
153+ {
154+ Func < object ? > f => ( key , await f . ResolveAsync ( ) ) ,
155+ Task t => ( key , await t . ResolveResult ( ) ) ,
156+ InvokableProp p => ( key , await p . Invoke ( ) ) ,
157+ _ => ( key , pair . Value )
158+ } ;
159+
160+ if ( value . Item2 is Dictionary < string , object ? > dict )
161+ {
162+ value = ( key , await ResolvePropertyInstances ( dict ) ) ;
163+ }
164+
165+ return value ;
166+ } ) ) ) . ToDictionary ( pair => pair . key , pair => pair . Item2 ) ;
64167 }
65168
66169 protected internal JsonResult GetJson ( )
@@ -93,7 +196,7 @@ private ViewResult GetView()
93196
94197 protected internal IActionResult GetResult ( ) => _context ! . IsInertiaRequest ( ) ? GetJson ( ) : GetView ( ) ;
95198
96- private IDictionary < string , string > GetErrors ( )
199+ private Dictionary < string , string > GetErrors ( )
97200 {
98201 if ( ! _context ! . ModelState . IsValid )
99202 return _context ! . ModelState . ToDictionary ( o => o . Key . ToCamelCase ( ) ,
@@ -111,48 +214,4 @@ public Response WithViewData(IDictionary<string, object> viewData)
111214 _viewData = viewData ;
112215 return this ;
113216 }
114-
115- private async Task < Dictionary < string , object ? > > ResolveProperties ( Dictionary < string , object ? > props )
116- {
117- var isPartial = _context ! . IsInertiaPartialComponent ( _component ) ;
118-
119- if ( ! isPartial )
120- {
121- props = props
122- . Where ( kv => kv . Value is not LazyProp )
123- . ToDictionary ( kv => kv . Key , kv => kv . Value ) ;
124- }
125- else
126- {
127- props = props . ToDictionary ( kv => kv . Key , kv => kv . Value ) ;
128-
129- if ( _context ! . HttpContext . Request . Headers . ContainsKey ( InertiaHeader . PartialOnly ) )
130- props = ResolveOnly ( props ) ;
131-
132- if ( _context ! . HttpContext . Request . Headers . ContainsKey ( InertiaHeader . PartialExcept ) )
133- props = ResolveExcept ( props ) ;
134- }
135-
136- props = ResolveAlways ( props ) ;
137- props = await PrepareProps ( props ) ;
138-
139- return props ;
140- }
141-
142- private Dictionary < string , object ? > ResolveOnly ( Dictionary < string , object ? > props )
143- => _context ! . OnlyProps ( props ) ;
144-
145- private Dictionary < string , object ? > ResolveExcept ( Dictionary < string , object ? > props )
146- => _context ! . ExceptProps ( props ) ;
147-
148- private Dictionary < string , object ? > ResolveAlways ( Dictionary < string , object ? > props )
149- {
150- var alwaysProps = _props . GetType ( ) . GetProperties ( )
151- . Where ( o => o . PropertyType == typeof ( AlwaysProp ) )
152- . ToDictionary ( o => o . Name . ToCamelCase ( ) , o => o . GetValue ( _props ) ) ;
153-
154- return props
155- . Where ( kv => kv . Value is not AlwaysProp )
156- . Concat ( alwaysProps ) . ToDictionary ( kv => kv . Key , kv => kv . Value ) ;
157- }
158217}
0 commit comments