Skip to content

Commit a8769e9

Browse files
committed
Refactored all commands to support full configuration based naming and auto registration with library loaders.
1 parent d3244bc commit a8769e9

24 files changed

Lines changed: 1428 additions & 169 deletions

src/Architecture/CodeFactory.Architecture.Blazor.Server/AddMissingControllerMembers.cs renamed to src/Architecture/CodeFactory.Architecture.Blazor.Server/CSharpFile/AddMissingControllerMembers.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
using System.Threading.Tasks;
1717
using System.Windows;
1818

19-
namespace CodeFactory.Architecture.Blazor.Server
19+
namespace CodeFactory.Architecture.Blazor.Server.CSharpFile
2020
{
2121
/// <summary>
2222
/// Code factory command for automation of a C# document when selected from a project in solution explorer.

src/Architecture/CodeFactory.Architecture.Blazor.Server/AddMissingLogicMembers.cs renamed to src/Architecture/CodeFactory.Architecture.Blazor.Server/CSharpFile/AddMissingLogicMembers.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
using System.Threading.Tasks;
1515
using System.Windows;
1616

17-
namespace CodeFactory.Architecture.Blazor.Server
17+
namespace CodeFactory.Architecture.Blazor.Server.CSharpFile
1818
{
1919
/// <summary>
2020
/// Code factory command for automation of a C# document when selected from a project in solution explorer.
@@ -210,9 +210,8 @@ public override async Task ExecuteCommandAsync(VsCSharpSource result)
210210

211211
var boundChecks = new List<IBoundsCheckBlock>
212212
{
213-
214-
new BoundsCheckBlockNullNDFException(true,loggerBlock),
215-
new BoundsCheckBlockStringNDFException(true,loggerBlock)
213+
new BoundsCheckBlockStringNDFException(true,loggerBlock),
214+
new BoundsCheckBlockNullNDFException(true,loggerBlock)
216215
};
217216

218217
var tryBlock = new TryBlockStandard(loggerBlock,catchBlocks);

src/Architecture/CodeFactory.Architecture.Blazor.Server/AddMissingRepositoryMembers.cs renamed to src/Architecture/CodeFactory.Architecture.Blazor.Server/CSharpFile/AddMissingRepositoryMembers.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
using System.Threading.Tasks;
1717
using System.Windows;
1818

19-
namespace CodeFactory.Architecture.Blazor.Server
19+
namespace CodeFactory.Architecture.Blazor.Server.CSharpFile
2020
{
2121
/// <summary>
2222
/// Code factory command for automation of a C# document when selected from a project in solution explorer.

src/Architecture/CodeFactory.Architecture.Blazor.Server/RefreshEFRepository.cs renamed to src/Architecture/CodeFactory.Architecture.Blazor.Server/CSharpFile/RefreshEFRepository.cs

Lines changed: 142 additions & 67 deletions
Large diffs are not rendered by default.

src/Architecture/CodeFactory.Architecture.Blazor.Server/RefreshFluentValidation.cs renamed to src/Architecture/CodeFactory.Architecture.Blazor.Server/CSharpFile/RefreshFluentValidation.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
using System.Linq;
1313
using System.Text;
1414
using System.Threading.Tasks;
15+
using System.Windows;
1516

16-
namespace CodeFactory.Architecture.Blazor.Server
17+
namespace CodeFactory.Architecture.Blazor.Server.CSharpFile
1718
{
1819
/// <summary>
1920
/// Code factory command for automation of a C# document when selected from a project in solution explorer.
@@ -177,6 +178,10 @@ await VisualStudioActions.GetProjectFromConfigAsync(command.ExecutionProject)
177178

178179
var validationClass = VisualStudioActions.RefreshValidationAsync(sourceClass, sourceProject,sourceFolder,nameManagement);
179180
}
181+
catch (CodeFactoryException codeFactoryError)
182+
{
183+
MessageBox.Show(codeFactoryError.Message, "Automation Error", MessageBoxButton.OK, MessageBoxImage.Error);
184+
}
180185
catch (Exception unhandledError)
181186
{
182187
_logger.Error($"The following unhandled error occurred while executing the solution explorer C# document command {commandTitle}. ",
Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
using CodeFactory.Automation.NDF.Logic.General;
2+
using CodeFactory.Automation.Standard.Logic;
3+
using CodeFactory.WinVs;
4+
using CodeFactory.WinVs.Commands;
5+
using CodeFactory.WinVs.Commands.SolutionExplorer;
6+
using CodeFactory.WinVs.Logging;
7+
using CodeFactory.WinVs.Models.CSharp;
8+
using CodeFactory.WinVs.Models.CSharp.Builder;
9+
using CodeFactory.WinVs.Models.ProjectSystem;
10+
using System;
11+
using System.Collections.Generic;
12+
using System.Linq;
13+
using System.Text;
14+
using System.Threading.Tasks;
15+
using System.Windows;
16+
17+
namespace CodeFactory.Architecture.Blazor.Server.CSharpFile
18+
{
19+
/// <summary>
20+
/// Code factory command for automation of a C# document when selected from a project in solution explorer.
21+
/// </summary>
22+
public class RefreshLogic : CSharpSourceCommandBase
23+
{
24+
private static readonly string commandTitle = "Refresh Logic";
25+
private static readonly string commandDescription = "Refreshes the logic implementation for the target logic interface.";
26+
27+
#pragma warning disable CS1998
28+
29+
/// <inheritdoc />
30+
public RefreshLogic(ILogger logger, IVsActions vsActions) : base(logger, vsActions, commandTitle, commandDescription)
31+
{
32+
//Intentionally blank
33+
}
34+
35+
#region External Configuration
36+
37+
/// <summary>
38+
/// The fully qualified name of the command to be used with configuration.
39+
/// </summary>
40+
public static string Type = typeof(RefreshLogic).FullName;
41+
42+
/// <summary>
43+
/// Exection project for the command.
44+
/// </summary>
45+
public static string ExecutionProject = "ExecutionProject";
46+
47+
/// <summary>
48+
/// Execution folder for the command.
49+
/// </summary>
50+
public static string ExecutionFolder = "ExecutionFolder";
51+
52+
/// <summary>
53+
/// The logic project that holds the logic class to be refreshed.
54+
/// </summary>
55+
public static string LogicProject = "LogicProject";
56+
57+
/// <summary>
58+
/// Optional, folder where the logic class it be refreshed is located.
59+
/// </summary>
60+
public static string LogicFolder = "LogicFolder";
61+
62+
/// <summary>
63+
/// Optional, comma seperated value list of prefixes to be removed from the logic contracts name.
64+
/// </summary>
65+
public static string RemovePrefixes = "RemovePrefixes";
66+
67+
/// <summary>
68+
/// Optional, comma seperated value list of the suffixes to be removed from the logic contract name.
69+
/// </summary>
70+
public static string RemoveSuffixes = "RemoveSuffixes";
71+
72+
/// <summary>
73+
/// Optional, the prefix to append to the logic class name.
74+
/// </summary>
75+
public static string LogicPrefix = "LogicPrefix";
76+
77+
/// <summary>
78+
/// Optional, the suffix to append to the logic class name.
79+
/// </summary>
80+
public static string LogicSuffix = "LogicSuffix";
81+
82+
/// <summary>
83+
/// Loads the external configuration definition for this command.
84+
/// </summary>
85+
/// <returns>Will return the command configuration or null if this command does not support external configurations.</returns>
86+
public override ConfigCommand LoadExternalConfigDefinition()
87+
{
88+
return new ConfigCommand { Name = commandTitle, Category = "Logic", CommandType = Type, }
89+
.UpdateExecutionProject
90+
(
91+
new ConfigProject
92+
{
93+
Name = ExecutionProject,
94+
Guidance = "Project that contains the interface that triggers the automation."
95+
}
96+
.AddFolder
97+
(
98+
new ConfigFolder
99+
{
100+
Name = ExecutionFolder,
101+
Required = false,
102+
Guidance = "Optional, project folder that contains the interface that triggers the automation."
103+
}
104+
)
105+
.AddParameter
106+
(
107+
new ConfigParameter
108+
{
109+
Name = RemovePrefixes,
110+
Guidance = "Optional, comma seperated value list of prefix values to remove from the interface name."
111+
}
112+
)
113+
.AddParameter
114+
(
115+
new ConfigParameter
116+
{
117+
Name = RemoveSuffixes,
118+
Guidance = "Optional, comma seperated value list of suffix values to remove from the interface name."
119+
}
120+
)
121+
122+
)
123+
.AddProject
124+
(
125+
new ConfigProject
126+
{
127+
Name = LogicProject,
128+
Guidance = "Name of the project that hosts the logic class to be refreshed."
129+
}
130+
.AddFolder
131+
(
132+
new ConfigFolder
133+
{
134+
Name = LogicFolder,
135+
Required = false,
136+
Guidance = "Optional, The project folder the logic class is hosted in."
137+
}
138+
)
139+
.AddParameter
140+
(
141+
new ConfigParameter
142+
{
143+
Name = LogicPrefix,
144+
Guidance = "Optional, the prefix to append to the logic class name."
145+
146+
}
147+
)
148+
.AddParameter
149+
(
150+
new ConfigParameter
151+
{
152+
Name = LogicSuffix,
153+
Guidance = "Optional, the suffix to append to the logic class name."
154+
155+
}
156+
)
157+
);
158+
159+
160+
}
161+
#endregion
162+
163+
#region Overrides of VsCommandBase<IVsCSharpDocument>
164+
165+
/// <summary>
166+
/// Validation logic that will determine if this command should be enabled for execution.
167+
/// </summary>
168+
/// <param name="result">The target model data that will be used to determine if this command should be enabled.</param>
169+
/// <returns>Boolean flag that will tell code factory to enable this command or disable it.</returns>
170+
public override async Task<bool> EnableCommandAsync(VsCSharpSource result)
171+
{
172+
//Result that determines if the command is enabled and visible in the context menu for execution.
173+
bool isEnabled = false;
174+
175+
try
176+
{
177+
178+
var logicContract = result.SourceCode?.Interfaces.FirstOrDefault();
179+
180+
isEnabled = logicContract != null;
181+
182+
ConfigCommand command = null;
183+
184+
if( isEnabled )
185+
{
186+
command = await ConfigManager.LoadCommandByFolderAsync(Type, ExecutionFolder, result)
187+
?? await ConfigManager.LoadCommandByProjectAsync(Type, result);
188+
189+
isEnabled = command != null;
190+
}
191+
192+
if(isEnabled) isEnabled = await LogicNeedsUpdatesAsync(command,logicContract);
193+
194+
}
195+
catch (Exception unhandledError)
196+
{
197+
_logger.Error($"The following unhandled error occurred while checking if the solution explorer C# document command {commandTitle} is enabled. ",
198+
unhandledError);
199+
isEnabled = false;
200+
}
201+
202+
return isEnabled;
203+
}
204+
205+
/// <summary>
206+
/// Code factory framework calls this method when the command has been executed.
207+
/// </summary>
208+
/// <param name="result">The code factory model that has generated and provided to the command to process.</param>
209+
public override async Task ExecuteCommandAsync(VsCSharpSource result)
210+
{
211+
try
212+
{
213+
var logicContract = result.SourceCode?.Interfaces.FirstOrDefault()
214+
?? throw new CodeFactoryException("Could not load the source interface cannot refresh the logic.");
215+
216+
var commandConfig = await ConfigManager.LoadCommandByFolderAsync(Type, ExecutionFolder, result)
217+
?? await ConfigManager.LoadCommandByProjectAsync(Type, result)
218+
?? throw new CodeFactoryException("Could not load the configuratin, cannot refresh the logic");
219+
220+
var logicName = GenerateLogicClassName(commandConfig,logicContract)
221+
?? throw new CodeFactoryException("Could not determine the logic class name, cannot refresh the logic");
222+
223+
var contractProject = await VisualStudioActions.GetProjectFromConfigAsync(commandConfig.ExecutionProject)
224+
?? throw new CodeFactoryException("Cannot load the contract interface project, cannot refresh the logic");
225+
226+
var contractProjectFolder = await VisualStudioActions.GetProjectFolderFromConfigAsync(commandConfig.ExecutionProject,ExecutionFolder);
227+
228+
var logicProject = await VisualStudioActions.GetProjectFromConfigAsync(commandConfig.Project(LogicProject))
229+
?? throw new CodeFactoryException("Could not load the logic project, cannot refresh the logic.");
230+
231+
var logicProjectFolder = await VisualStudioActions.GetProjectFolderFromConfigAsync(commandConfig.Project(LogicProject),LogicFolder);
232+
233+
await VisualStudioActions.RefreshLogicAsync(logicName,logicContract.Name,logicProject,contractProject,logicFolder:logicProjectFolder,contractFolder: contractProjectFolder);
234+
235+
}
236+
catch (CodeFactoryException codeFactoryError)
237+
{
238+
MessageBox.Show(codeFactoryError.Message, "Automation Error", MessageBoxButton.OK, MessageBoxImage.Error);
239+
}
240+
catch (Exception unhandledError)
241+
{
242+
_logger.Error($"The following unhandled error occurred while executing the solution explorer C# document command {commandTitle}. ",
243+
unhandledError);
244+
245+
}
246+
247+
}
248+
249+
#endregion
250+
251+
/// <summary>
252+
/// Helper method that determines if the command should be activated. Checks to make sure all the conditions are met to refresh the logic.
253+
/// </summary>
254+
/// <param name="command">The commands configuration.</param>
255+
/// <param name="interfaceContract">The source interface that is being used to refresh the logic.</param>
256+
/// <returns>True if the command should be enabled, false if not.</returns>
257+
private async Task<bool> LogicNeedsUpdatesAsync(ConfigCommand command,CsInterface interfaceContract)
258+
{
259+
260+
var logicProject = await VisualStudioActions.GetProjectFromConfigAsync(command.Project(LogicProject));
261+
262+
if(logicProject == null) return false;
263+
264+
var logicFolder = await VisualStudioActions.GetProjectFolderFromConfigAsync(command.Project(LogicProject),LogicFolder);
265+
266+
var logicClassName = GenerateLogicClassName(command,interfaceContract);
267+
268+
if(logicClassName == null) return false;
269+
270+
var logicSource = logicFolder != null
271+
? await logicFolder.FindCSharpSourceByClassNameAsync(logicClassName,false)
272+
: await logicProject.FindCSharpSourceByClassNameAsync(logicClassName,false);
273+
274+
if(logicSource == null) return true;
275+
276+
var logicClass = logicSource?.SourceCode?.Classes?.FirstOrDefault();
277+
278+
if(logicClass == null) return false;
279+
280+
return logicClass.GetMissingInterfaceMembers().Any();
281+
282+
}
283+
284+
/// <summary>
285+
/// Generates the name of the logic class to be refreshed.
286+
/// </summary>
287+
/// <param name="command">The command configuration to use to generate the class name.</param>
288+
/// <param name="interfaceContract">The interface that implements the logic class to refresh.</param>
289+
/// <returns>Formatted name or null if the name cannot be determined.</returns>
290+
private string GenerateLogicClassName(ConfigCommand command,CsInterface interfaceContract)
291+
{
292+
if(command == null) return null;
293+
294+
if(interfaceContract == null) return null;
295+
296+
var removePrefixes = command.ExecutionProject.ParameterValue(RemovePrefixes);
297+
var removeSuffixes = command.ExecutionProject.ParameterValue(RemoveSuffixes);
298+
var logicPrefix = command.Project(LogicProject).ParameterValue(LogicPrefix);
299+
var logicSuffix = command.Project(LogicProject).ParameterValue(LogicSuffix);
300+
301+
return NameManagement.Init(removePrefixes,removeSuffixes, logicPrefix, logicSuffix).FormatName(interfaceContract.Name.GenerateCSharpFormattedClassName());
302+
303+
}
304+
}
305+
}

src/Architecture/CodeFactory.Architecture.Blazor.Server/RefreshRestService.cs renamed to src/Architecture/CodeFactory.Architecture.Blazor.Server/CSharpFile/RefreshRestService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
using System.Threading.Tasks;
1515
using System.Windows;
1616

17-
namespace CodeFactory.Architecture.Blazor.Server
17+
namespace CodeFactory.Architecture.Blazor.Server.CSharpFile
1818
{
1919
/// <summary>
2020
/// Code factory command for automation of a C# document when selected from a project in solution explorer.

0 commit comments

Comments
 (0)