11using System ;
22using System . Collections . Generic ;
33using System . Linq ;
4+ using System . Text ;
5+ using DiffPlex ;
6+ using DiffPlex . DiffBuilder ;
7+ using DiffPlex . DiffBuilder . Model ;
48using KustoSchemaTools . Model ;
59
610namespace KustoSchemaTools . Changes
@@ -36,6 +40,7 @@ public static StructuredChange ToStructuredChange(this IChange change)
3640 case ScriptCompareChange scriptCompare :
3741 structuredChange . ChangeType = scriptCompare . From == null ? "Create" : "Update" ;
3842 structuredChange . ScriptComparison = scriptCompare . ToStructuredScriptComparison ( ) ;
43+ structuredChange . DiffMarkdown = BuildDiffMarkdown ( scriptCompare ) ;
3944 break ;
4045 default :
4146 structuredChange . ChangeType = "Update" ;
@@ -69,6 +74,12 @@ public static StructuredChange ToStructuredChange(this IChange change)
6974 comparison . OldScripts . Add ( CloneScript ( previous ) ) ;
7075 }
7176 }
77+
78+ var validationPayload = BuildValidationPayload ( previousScripts , comparison . NewScripts ) ;
79+ if ( validationPayload . Count > 0 )
80+ {
81+ comparison . ValidationResults = validationPayload ;
82+ }
7283 }
7384
7485 foreach ( var script in comparison . OldScripts . Where ( s => ! s . IsValid . HasValue ) )
@@ -86,7 +97,129 @@ private static DatabaseScriptContainer CloneScript(DatabaseScriptContainer sourc
8697 IsValid = source . IsValid
8798 } ;
8899
100+ if ( source . Diagnostics != null && source . Diagnostics . Count > 0 )
101+ {
102+ clone . Diagnostics = source . Diagnostics
103+ . Select ( diagnostic => new ScriptDiagnostic
104+ {
105+ Start = diagnostic . Start ,
106+ End = diagnostic . End ,
107+ Description = diagnostic . Description
108+ } )
109+ . ToList ( ) ;
110+ }
111+
89112 return clone ;
90113 }
114+
115+ private static Dictionary < string , object ? > BuildValidationPayload ( Dictionary < string , DatabaseScriptContainer > previousScripts , List < DatabaseScriptContainer > newScripts )
116+ {
117+ var payload = new Dictionary < string , object ? > ( ) ;
118+ foreach ( var script in newScripts )
119+ {
120+ var oldScript = previousScripts . ContainsKey ( script . Kind ) ? previousScripts [ script . Kind ] : null ;
121+ var diffPreview = BuildDiffPreview ( oldScript , script ) ;
122+ if ( diffPreview . Count > 0 )
123+ {
124+ var keyName = string . IsNullOrWhiteSpace ( script . Kind ) ? "diff" : $ "diff::{ script . Kind } ";
125+ payload [ keyName ] = diffPreview ;
126+ }
127+ }
128+
129+ return payload ;
130+ }
131+
132+ private static List < string > BuildDiffPreview ( DatabaseScriptContainer ? oldScript , DatabaseScriptContainer ? newScript )
133+ {
134+ var before = GetScriptText ( oldScript ) ;
135+ var after = GetScriptText ( newScript ) ;
136+
137+ if ( string . Equals ( before , after , StringComparison . Ordinal ) )
138+ {
139+ return new List < string > ( ) ;
140+ }
141+
142+ var differ = new Differ ( ) ;
143+ var diff = InlineDiffBuilder . Diff ( before , after , false ) ;
144+
145+ var preview = diff . Lines
146+ . Where ( line => line . Type != ChangeType . Unchanged )
147+ . Select ( line =>
148+ {
149+ var prefix = line . Type switch
150+ {
151+ ChangeType . Inserted => "+" ,
152+ ChangeType . Deleted => "-" ,
153+ ChangeType . Modified => "~" ,
154+ _ => " "
155+ } ;
156+ return $ "{ prefix } { line . Text ? . TrimEnd ( ) } ";
157+ } )
158+ . Where ( line => ! string . IsNullOrWhiteSpace ( line ) )
159+ . Take ( 10 )
160+ . ToList ( ) ;
161+
162+ return preview ;
163+ }
164+
165+ private static string GetScriptText ( DatabaseScriptContainer ? script )
166+ {
167+ return script ? . Script ? . Text ?? string . Empty ;
168+ }
169+
170+ private static string ? BuildDiffMarkdown ( ScriptCompareChange change )
171+ {
172+ var previousScripts = change . From ?
173+ . CreateScripts ( change . Entity , false )
174+ . GroupBy ( script => script . Kind )
175+ . Select ( group => group . First ( ) )
176+ . ToDictionary ( script => script . Kind , script => script )
177+ ?? new Dictionary < string , DatabaseScriptContainer > ( ) ;
178+
179+ var sb = new StringBuilder ( ) ;
180+ var differ = new Differ ( ) ;
181+ foreach ( var script in change . Scripts )
182+ {
183+ var before = previousScripts . TryGetValue ( script . Kind , out var prior )
184+ ? prior . Script ? . Text ?? string . Empty
185+ : string . Empty ;
186+ var after = script . Script ? . Text ?? string . Empty ;
187+
188+ if ( string . Equals ( before , after , StringComparison . Ordinal ) )
189+ {
190+ continue ;
191+ }
192+
193+ var diff = InlineDiffBuilder . Diff ( before , after , false ) ;
194+ var hasMeaningfulDiff = diff . Lines . Any ( line => line . Type != ChangeType . Unchanged ) ;
195+ if ( ! hasMeaningfulDiff )
196+ {
197+ continue ;
198+ }
199+
200+ if ( ! string . IsNullOrWhiteSpace ( script . Kind ) )
201+ {
202+ sb . AppendLine ( $ "// { script . Kind } ") ;
203+ }
204+
205+ sb . AppendLine ( "```diff" ) ;
206+ foreach ( var line in diff . Lines )
207+ {
208+ var prefix = line . Type switch
209+ {
210+ ChangeType . Inserted => "+" ,
211+ ChangeType . Deleted => "-" ,
212+ ChangeType . Modified => "~" ,
213+ _ => " "
214+ } ;
215+ sb . AppendLine ( $ "{ prefix } { line . Text } ") ;
216+ }
217+ sb . AppendLine ( "```" ) ;
218+ sb . AppendLine ( ) ;
219+ }
220+
221+ var diffContent = sb . ToString ( ) . Trim ( ) ;
222+ return string . IsNullOrEmpty ( diffContent ) ? null : diffContent ;
223+ }
91224 }
92225}
0 commit comments