diff --git a/src/PSRule.Types/Definitions/ResourceHelper.cs b/src/PSRule.Types/Definitions/ResourceHelper.cs index d56611e438..4815ccf681 100644 --- a/src/PSRule.Types/Definitions/ResourceHelper.cs +++ b/src/PSRule.Types/Definitions/ResourceHelper.cs @@ -11,7 +11,7 @@ internal static class ResourceHelper private const char SCOPE_SEPARATOR = '\\'; - internal const string STANDALONE_SCOPENAME = "."; + internal const string STANDALONE_SCOPE_NAME = "."; internal static string GetIdString(string scope, string name) { @@ -63,7 +63,7 @@ internal static void ParseIdString(string id, out string? scope, out string? nam internal static ResourceId GetRuleId(string? defaultScope, string name, ResourceIdKind kind) { - defaultScope ??= STANDALONE_SCOPENAME; + defaultScope ??= STANDALONE_SCOPE_NAME; return name.IndexOf(SCOPE_SEPARATOR) > 0 ? ResourceId.Parse(name, kind) : new ResourceId(defaultScope, name, kind); } @@ -87,6 +87,6 @@ internal static SeverityLevel GetLevel(SeverityLevel? level) internal static string NormalizeScope(string? scope) { - return scope == null || string.IsNullOrEmpty(scope) ? STANDALONE_SCOPENAME : scope; + return scope == null || string.IsNullOrEmpty(scope) ? STANDALONE_SCOPE_NAME : scope; } } diff --git a/src/PSRule.Types/Definitions/ResourceId.cs b/src/PSRule.Types/Definitions/ResourceId.cs index 593bb0c386..50eafff381 100644 --- a/src/PSRule.Types/Definitions/ResourceId.cs +++ b/src/PSRule.Types/Definitions/ResourceId.cs @@ -134,7 +134,7 @@ private static bool TryParse(string id, ResourceIdKind kind, out ResourceId? val if (string.IsNullOrEmpty(id) || !TryParse(id, out var scope, out var name) || name == null) return false; - scope ??= ResourceHelper.STANDALONE_SCOPENAME; + scope ??= ResourceHelper.STANDALONE_SCOPE_NAME; value = new ResourceId(id, scope, name, kind); return true; } diff --git a/src/PSRule/Commands/NewRuleDefinitionCommand.cs b/src/PSRule/Commands/NewRuleDefinitionCommand.cs index 7114b71187..7a1bdb10fe 100644 --- a/src/PSRule/Commands/NewRuleDefinitionCommand.cs +++ b/src/PSRule/Commands/NewRuleDefinitionCommand.cs @@ -14,6 +14,7 @@ namespace PSRule.Commands; /// /// A Rule language block. +/// When processed, creates a rule language element that can be used later during rule execution. /// [Cmdlet(VerbsCommon.New, RuleLanguageNouns.RuleDefinition)] internal sealed class NewRuleDefinitionCommand : LanguageBlock @@ -89,7 +90,7 @@ internal sealed class NewRuleDefinitionCommand : LanguageBlock public string[] Alias { get; set; } /// - /// An optional reference identifer for the resource. + /// An optional reference identifier for the resource. /// [Parameter(Mandatory = false)] [ValidateLength(3, 128)] diff --git a/src/PSRule/Definitions/ResourceValidator.cs b/src/PSRule/Definitions/ResourceValidator.cs index 4894cd00a1..4080a81e0c 100644 --- a/src/PSRule/Definitions/ResourceValidator.cs +++ b/src/PSRule/Definitions/ResourceValidator.cs @@ -3,8 +3,8 @@ using System.Management.Automation; using System.Text.RegularExpressions; +using PSRule.Pipeline; using PSRule.Resources; -using PSRule.Runtime; namespace PSRule.Definitions; @@ -22,11 +22,11 @@ internal sealed class ResourceValidator : IResourceValidator private static readonly Regex ValidName = new("^[^<>:/\\\\|?*\"'`+@._\\-\x00-\x1F][^<>:/\\\\|?*\"'`+@\x00-\x1F]{1,126}[^<>:/\\\\|?*\"'`+@._\\-\x00-\x1F]$", RegexOptions.Compiled, TimeSpan.FromSeconds(5)); - private readonly RunspaceContext _Context; + private readonly IPipelineWriter _Writer; - public ResourceValidator(RunspaceContext context) + public ResourceValidator(IPipelineWriter writer) { - _Context = context; + _Writer = writer; } internal static bool IsNameValid(string name) @@ -74,7 +74,7 @@ private static string ReportExtent(ISourceExtent extent) private void ReportError(string errorId, string message, params object[] args) { - if (_Context == null) + if (_Writer == null) return; ReportError(new Pipeline.ParseException( @@ -85,10 +85,10 @@ private void ReportError(string errorId, string message, params object[] args) private void ReportError(Pipeline.ParseException exception) { - if (_Context == null) + if (_Writer == null) return; - _Context.WriteError(new ErrorRecord( + _Writer.WriteError(new ErrorRecord( exception: exception, errorId: exception.ErrorId, errorCategory: ErrorCategory.InvalidOperation, diff --git a/src/PSRule/Host/HostHelper.cs b/src/PSRule/Host/HostHelper.cs index 8fa94597cf..f955598458 100644 --- a/src/PSRule/Host/HostHelper.cs +++ b/src/PSRule/Host/HostHelper.cs @@ -247,7 +247,7 @@ private static ILanguageBlock[] GetPSLanguageBlocks(RunspaceContext context, Sou private static ILanguageBlock[] GetYamlLanguageBlocks(Source[] sources, RunspaceContext context) { var result = new Collection(); - var visitor = new ResourceValidator(context); + var visitor = new ResourceValidator(context.Writer); var d = new DeserializerBuilder() .IgnoreUnmatchedProperties() .WithNamingConvention(CamelCaseNamingConvention.Instance) @@ -313,7 +313,7 @@ private static ILanguageBlock[] GetYamlLanguageBlocks(Source[] sources, Runspace private static ILanguageBlock[] GetJsonLanguageBlocks(Source[] sources, RunspaceContext context) { var result = new Collection(); - var visitor = new ResourceValidator(context); + var visitor = new ResourceValidator(context.Writer); var deserializer = new JsonSerializer { DateTimeZoneHandling = DateTimeZoneHandling.Utc diff --git a/src/PSRule/Pipeline/IPipelineReader.cs b/src/PSRule/Pipeline/IPipelineReader.cs new file mode 100644 index 0000000000..6f367c1ab3 --- /dev/null +++ b/src/PSRule/Pipeline/IPipelineReader.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using PSRule.Data; + +namespace PSRule.Pipeline; + +internal interface IPipelineReader +{ + int Count { get; } + + bool IsEmpty { get; } + + /// + /// Add a new object into the stream. + /// + /// An object to process. + /// A pre-bound type. + /// Determines if expansion is skipped. + void Enqueue(object sourceObject, string? targetType = null, bool skipExpansion = false); + + bool TryDequeue(out ITargetObject sourceObject); + + void Open(); + + /// + /// Add a path to the list of inputs. + /// + /// The path of files to add. + void Add(string path); +} + +#nullable restore diff --git a/src/PSRule/Pipeline/OptionContextBuilder.cs b/src/PSRule/Pipeline/OptionContextBuilder.cs index 8b26e2495f..d8cc7e5193 100644 --- a/src/PSRule/Pipeline/OptionContextBuilder.cs +++ b/src/PSRule/Pipeline/OptionContextBuilder.cs @@ -119,7 +119,7 @@ internal void ModuleConfig(string module, ModuleConfigV1Spec spec) private static bool ShouldCombine(string languageScope, OptionScope optionScope) { - return optionScope.LanguageScope == ResourceHelper.STANDALONE_SCOPENAME || optionScope.LanguageScope == languageScope || optionScope.Type == ScopeType.Explicit; + return optionScope.LanguageScope == ResourceHelper.STANDALONE_SCOPE_NAME || optionScope.LanguageScope == languageScope || optionScope.Type == ScopeType.Explicit; } /// diff --git a/src/PSRule/Pipeline/PipelineContext.cs b/src/PSRule/Pipeline/PipelineContext.cs index 1e46fa7654..cfbb491be8 100644 --- a/src/PSRule/Pipeline/PipelineContext.cs +++ b/src/PSRule/Pipeline/PipelineContext.cs @@ -114,27 +114,6 @@ public string[] SourceContentCache } } - internal enum ResourceIssueType - { - Unknown - } - - internal sealed class ResourceIssue - { - public ResourceIssue(ResourceKind kind, string id, ResourceIssueType issue) - { - Kind = kind; - Id = id; - Issue = issue; - } - - public ResourceKind Kind { get; } - - public string Id { get; } - - public ResourceIssueType Issue { get; } - } - internal Runspace GetRunspace() { if (_Runspace == null) diff --git a/src/PSRule/Pipeline/ResourceIssue.cs b/src/PSRule/Pipeline/ResourceIssue.cs new file mode 100644 index 0000000000..d9ca6c899c --- /dev/null +++ b/src/PSRule/Pipeline/ResourceIssue.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using PSRule.Definitions; + +namespace PSRule.Pipeline; + +internal sealed class ResourceIssue +{ + public ResourceIssue(ResourceKind resourceKind, ResourceId resourceId, ResourceIssueType issue) + { + ResourceKind = resourceKind; + ResourceId = resourceId; + Issue = issue; + } + + public ResourceKind ResourceKind { get; } + + public ResourceId ResourceId { get; } + + public ResourceIssueType Issue { get; } +} diff --git a/src/PSRule/Pipeline/ResourceIssueType.cs b/src/PSRule/Pipeline/ResourceIssueType.cs new file mode 100644 index 0000000000..ba4ee36301 --- /dev/null +++ b/src/PSRule/Pipeline/ResourceIssueType.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace PSRule.Pipeline; + +internal enum ResourceIssueType +{ + Unknown, + + SuppressionGroupExpired +} diff --git a/src/PSRule/Pipeline/TargetBinder.cs b/src/PSRule/Pipeline/TargetBinder.cs index d26ed9bf04..1aeda6e158 100644 --- a/src/PSRule/Pipeline/TargetBinder.cs +++ b/src/PSRule/Pipeline/TargetBinder.cs @@ -72,7 +72,7 @@ public TargetBinderBuilder(BindTargetMethod bindTargetName, BindTargetMethod bin _BindTargetName = bindTargetName; _BindTargetType = bindTargetType; _BindField = bindField; - _BindingContext = new List(); + _BindingContext = []; if (typeFilter != null && typeFilter.Length > 0) _TypeFilter = new HashSet(typeFilter, StringComparer.OrdinalIgnoreCase); } @@ -82,7 +82,7 @@ public TargetBinderBuilder(BindTargetMethod bindTargetName, BindTargetMethod bin /// public ITargetBinder Build() { - return new TargetBinder(_BindingContext.ToArray()); + return new TargetBinder([.. _BindingContext]); } /// @@ -114,8 +114,8 @@ internal sealed class TargetBinder : ITargetBinder internal TargetBinder(ITargetBindingContext[] bindingContext) { - _BindingContext = new Dictionary(); - _BindingResult = new Dictionary(); + _BindingContext = []; + _BindingResult = []; for (var i = 0; bindingContext != null && i < bindingContext.Length; i++) _BindingContext.Add(bindingContext[i].LanguageScope ?? STANDALONE_SCOPE, bindingContext[i]); } diff --git a/src/PSRule/Runtime/ILanguageScope.cs b/src/PSRule/Runtime/ILanguageScope.cs index fed742553c..50c7907b19 100644 --- a/src/PSRule/Runtime/ILanguageScope.cs +++ b/src/PSRule/Runtime/ILanguageScope.cs @@ -7,8 +7,11 @@ namespace PSRule.Runtime; +#nullable enable + /// /// A named scope for language elements. +/// Any elements in a language scope are not visible to language elements in another scope. /// internal interface ILanguageScope : IDisposable { @@ -29,14 +32,17 @@ internal interface ILanguageScope : IDisposable /// /// Try to get a specific configuration value by name. /// - bool TryConfigurationValue(string key, out object value); + bool TryConfigurationValue(string key, out object? value); + /// + /// Add a filter to the language scope. + /// void WithFilter(IResourceFilter resourceFilter); /// /// Get a filter for a specific resource kind. /// - IResourceFilter GetFilter(ResourceKind kind); + IResourceFilter? GetFilter(ResourceKind kind); /// /// Add a service to the scope. @@ -46,11 +52,22 @@ internal interface ILanguageScope : IDisposable /// /// Get a previously added service. /// - object GetService(string name); + object? GetService(string name); - bool TryGetType(object o, out string type, out string path); + /// + /// Try to bind the type of the object. + /// + bool TryGetType(object o, out string? type, out string? path); - bool TryGetName(object o, out string name, out string path); + /// + /// Try to bind the name of the object. + /// + bool TryGetName(object o, out string? name, out string? path); - bool TryGetScope(object o, out string[] scope); + /// + /// Try to bind the scope of the object. + /// + bool TryGetScope(object o, out string[]? scope); } + +#nullable restore