Skip to content

Commit 219794d

Browse files
author
Kapil Borle
authored
Merge pull request #611 from PowerShell/kapilmb/RuleConfiguration
Add feature to pass parameters to rules from settings file
2 parents 1d6718c + a40da23 commit 219794d

File tree

8 files changed

+405
-170
lines changed

8 files changed

+405
-170
lines changed

Engine/Commands/InvokeScriptAnalyzerCommand.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,12 @@ public SwitchParameter SaveDscDependency
210210
/// </summary>
211211
protected override void BeginProcessing()
212212
{
213+
// Initialize helper
214+
Helper.Instance = new Helper(
215+
SessionState.InvokeCommand,
216+
this);
217+
Helper.Instance.Initialize();
218+
213219
string[] rulePaths = Helper.ProcessCustomRulePaths(customRulePath,
214220
this.SessionState, recurseCustomRulePath);
215221

Engine/Helper.cs

Lines changed: 79 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public class Helper
3535
private IOutputWriter outputWriter;
3636
private Object getCommandLock = new object();
3737
private readonly static Version minSupportedPSVersion = new Version(3, 0);
38+
private Dictionary<string, Dictionary<string, object>> ruleArguments;
3839

3940
#endregion
4041

@@ -113,14 +114,14 @@ internal set
113114
/// </summary>
114115
private Helper()
115116
{
116-
117+
117118
}
118119

119120
/// <summary>
120121
/// Initializes the Helper class.
121122
/// </summary>
122123
/// <param name="invokeCommand">
123-
/// A CommandInvocationIntrinsics instance for use in gathering
124+
/// A CommandInvocationIntrinsics instance for use in gathering
124125
/// information about available commands and aliases.
125126
/// </param>
126127
/// <param name="outputWriter">
@@ -145,6 +146,7 @@ public void Initialize()
145146
AliasToCmdletDictionary = new Dictionary<String, String>(StringComparer.OrdinalIgnoreCase);
146147
KeywordBlockDictionary = new Dictionary<String, List<Tuple<int, int>>>(StringComparer.OrdinalIgnoreCase);
147148
VariableAnalysisDictionary = new Dictionary<Ast, VariableAnalysis>();
149+
ruleArguments = new Dictionary<string, Dictionary<string, object>>(StringComparer.OrdinalIgnoreCase);
148150

149151
IEnumerable<CommandInfo> aliases = this.invokeCommand.GetCommands("*", CommandTypes.Alias, true);
150152

@@ -163,6 +165,59 @@ public void Initialize()
163165
}
164166
}
165167

168+
/// <summary>
169+
/// Returns all the rule arguments
170+
/// </summary>
171+
/// <returns>Dictionary that maps between rule name to their named arguments</returns>
172+
public Dictionary<string, Dictionary<string, object>> GetRuleArguments()
173+
{
174+
return ruleArguments;
175+
}
176+
177+
/// <summary>
178+
/// Get the parameters corresponding to the given rule name
179+
/// </summary>
180+
/// <param name="ruleName"></param>
181+
/// <returns>Dictionary of argument names mapped to values. If ruleName is not a valid key, returns null</returns>
182+
public Dictionary<string, object> GetRuleArguments(string ruleName)
183+
{
184+
if (ruleArguments.ContainsKey(ruleName))
185+
{
186+
return ruleArguments[ruleName];
187+
}
188+
return null;
189+
}
190+
191+
/// <summary>
192+
/// Sets the arguments for consumption by rules
193+
/// </summary>
194+
/// <param name="ruleArgs">A hashtable with rule names as keys</param>
195+
public void SetRuleArguments(Dictionary<string, object> ruleArgs)
196+
{
197+
if (ruleArgs == null)
198+
{
199+
return;
200+
}
201+
202+
if (ruleArgs.Comparer != StringComparer.OrdinalIgnoreCase)
203+
{
204+
throw new ArgumentException(
205+
"Input dictionary should have OrdinalIgnoreCase comparer.",
206+
"ruleArgs");
207+
}
208+
var ruleArgsDict = new Dictionary<string, Dictionary<string, object>>();
209+
foreach (var rule in ruleArgs.Keys)
210+
{
211+
var argsDict = ruleArgs[rule] as Dictionary<string, object>;
212+
if (argsDict == null)
213+
{
214+
return;
215+
}
216+
ruleArgsDict[rule] = argsDict;
217+
}
218+
ruleArguments = ruleArgsDict;
219+
}
220+
166221
/// <summary>
167222
/// Given a cmdlet, return the list of all the aliases.
168223
/// Also include the original name in the list.
@@ -231,7 +286,7 @@ public bool IsDscResourceModule(string filePath)
231286

232287
return false;
233288
}
234-
289+
235290
/// <summary>
236291
/// Gets the module manifest
237292
/// </summary>
@@ -471,13 +526,13 @@ private string NameWithoutScope(string name, string[] scopes)
471526
if (String.IsNullOrWhiteSpace(name) || scopes == null)
472527
{
473528
return name;
474-
}
529+
}
475530

476531
// checks whether function name starts with scope
477532
foreach (string scope in scopes)
478533
{
479534
// trim the scope part
480-
if (name.IndexOf(scope, StringComparison.OrdinalIgnoreCase) == 0)
535+
if (name.IndexOf(scope, StringComparison.OrdinalIgnoreCase) == 0)
481536

482537
{
483538
return name.Substring(scope.Length);
@@ -598,7 +653,7 @@ public bool PositionalParameterUsed(CommandAst cmdAst, bool moreThanThreePositio
598653
{
599654
arguments += 1;
600655
}
601-
656+
602657
}
603658

604659
// if not the first element in a pipeline, increase the number of arguments by 1
@@ -724,10 +779,10 @@ public IScriptExtent GetScriptExtentForFunctionName(FunctionDefinitionAst functi
724779
if (null == functionDefinitionAst)
725780
{
726781
return null;
727-
}
782+
}
728783
var funcNameTokens = Tokens.Where(
729-
token =>
730-
ContainsExtent(functionDefinitionAst.Extent, token.Extent)
784+
token =>
785+
ContainsExtent(functionDefinitionAst.Extent, token.Extent)
731786
&& token.Text.Equals(functionDefinitionAst.Name));
732787
var funcNameToken = funcNameTokens.FirstOrDefault();
733788
return funcNameToken == null ? null : funcNameToken.Extent;
@@ -919,7 +974,7 @@ internal VariableAnalysis InitializeVariableAnalysisHelper(Ast ast, VariableAnal
919974
/// <param name="classes"></param>
920975
/// <param name="scriptAst"></param>
921976
/// <returns></returns>
922-
977+
923978
#if PSV3
924979

925980
public string GetTypeFromReturnStatementAst(Ast funcAst, ReturnStatementAst ret)
@@ -990,7 +1045,7 @@ public string GetTypeFromReturnStatementAst(Ast funcAst, ReturnStatementAst ret,
9901045
/// <param name="scopeAst"></param>
9911046
/// <param name="classes"></param>
9921047
/// <returns></returns>
993-
1048+
9941049
#if PSV3
9951050

9961051
public string GetTypeFromMemberExpressionAst(MemberExpressionAst memberAst, Ast scopeAst)
@@ -1050,9 +1105,9 @@ public string GetTypeFromMemberExpressionAst(MemberExpressionAst memberAst, Ast
10501105
/// <param name="psClass"></param>
10511106
/// <param name="analysisDetails"></param>
10521107
/// <returns></returns>
1053-
1108+
10541109
#if PSV3
1055-
1110+
10561111
internal string GetTypeFromMemberExpressionAstHelper(MemberExpressionAst memberAst, VariableAnalysisDetails analysisDetails)
10571112

10581113
#else
@@ -1241,8 +1296,8 @@ internal List<RuleSuppression> GetSuppressionsClass(TypeDefinitionAst typeAst)
12411296

12421297
if (typeAst.Members == null)
12431298
{
1244-
return result;
1245-
}
1299+
return result;
1300+
}
12461301

12471302
foreach (var member in typeAst.Members)
12481303
{
@@ -1469,11 +1524,11 @@ public static string[] ProcessCustomRulePaths(string[] rulePaths, SessionState s
14691524
}
14701525
outPaths.Add(path);
14711526
}
1472-
1527+
14731528
return outPaths.ToArray();
1474-
1529+
14751530
}
1476-
1531+
14771532
/// <summary>
14781533
/// Check if the function name starts with one of potentailly state changing verbs
14791534
/// </summary>
@@ -1671,8 +1726,8 @@ public static IEnumerable<string> GetDeprecatedModuleManifestKeys()
16711726

16721727
/// <summary>
16731728
/// Get a mapping between string type keys and StatementAsts from module manifest hashtable ast
1674-
///
1675-
/// This is a workaround as SafeGetValue is not supported on PS v5 and below.
1729+
///
1730+
/// This is a workaround as SafeGetValue is not supported on PS v4 and below.
16761731
/// </summary>
16771732
/// <param name="hast">Hashtable Ast obtained from module manifest</param>
16781733
/// <returns>A dictionary that maps string keys to values of StatementAst type</returns>
@@ -1693,7 +1748,7 @@ private static Dictionary<string, StatementAst> GetMapFromHashtableAst(Hashtable
16931748

16941749
/// <summary>
16951750
/// Checks if the version is supported
1696-
///
1751+
///
16971752
/// PowerShell versions with Major greater than 3 are supported
16981753
/// </summary>
16991754
/// <param name="version">PowerShell version</param>
@@ -1910,7 +1965,7 @@ private object VisitStatementHelper(StatementAst statementAst)
19101965
#if PSV3
19111966

19121967
statementAst.Visit(this);
1913-
1968+
19141969
#else
19151970

19161971
TypeDefinitionAst typeAst = statementAst as TypeDefinitionAst;
@@ -2664,7 +2719,7 @@ static FindPipelineOutput()
26642719
/// Find the pipeline output
26652720
/// </summary>
26662721
/// <param name="ast"></param>
2667-
2722+
26682723
#if PSV3
26692724

26702725
public FindPipelineOutput(FunctionDefinitionAst ast)
@@ -2695,7 +2750,7 @@ public FindPipelineOutput(FunctionDefinitionAst ast, IEnumerable<TypeDefinitionA
26952750
/// Get list of outputTypes from functiondefinitionast funcast
26962751
/// </summary>
26972752
/// <returns></returns>
2698-
2753+
26992754
#if PSV3
27002755

27012756
public static List<Tuple<string, StatementAst>> OutputTypes(FunctionDefinitionAst funcAst)

0 commit comments

Comments
 (0)