public PathBasedPresetTreeExclusion(string excludedPath, PresetTreeRoot root) { _excludedPath = excludedPath; // path that does not start with / is relative to the parent include root path if (!_excludedPath.StartsWith("/")) { _excludedPath = $"{root.Path.TrimEnd('/')}/{_excludedPath}"; } // for legacy compatibility you can exclude children by having a path exclusion end with a trailing slash // but since we add a trailing slash internally to all paths (so that we match by path e.g. /foo != /foot) // we need to know if the original string had a trailing slash and handle it as a child exclusion _implicitChildrenExclusion = _excludedPath.EndsWith("/"); // we internally add a trailing slash to the excluded path, and add a trailing slash to the incoming evaluate path // why? because otherwise using StartsWith would mean that /foo would also exclude /foot. But /foo/ and /foot/ do not match like that. _excludedPath = PathTool.EnsureTrailingSlash(_excludedPath); }
public PredicateResult Evaluate(string itemPath) { itemPath = PathTool.EnsureTrailingSlash(itemPath); // you may preserve certain children from exclusion foreach (var exception in _exceptions) { if (itemPath.StartsWith(exception, StringComparison.OrdinalIgnoreCase)) { return(new PredicateResult(true)); } } // if the path isn't under the exclusion, it's included var wildcardFreePath = _excludeChildrenOfPath.EndsWith("/*/") ? _excludeChildrenOfPath.Substring(0, _excludeChildrenOfPath.Length - 2) : _excludeChildrenOfPath; if (!itemPath.StartsWith(wildcardFreePath, StringComparison.OrdinalIgnoreCase)) { return(new PredicateResult(true)); } // if the path EQUALS the exclusion path it's included. Because we're including the root, and excluding the children. if (itemPath.Equals(wildcardFreePath, StringComparison.OrdinalIgnoreCase)) { return(new PredicateResult(true)); } // if the path EQUALS a wildcarded exclusion path it's included. // we accomplish this by doing an equals on the parent path of both the item path and the exclusion // /foo/bar => /foo, then match against COP = /foo/* => /foo/ == TRUE, so we include it // but, /foo/bar/baz => /foo/bar, match against COP /foo/* => /foo/ == FALSE, so it is excluded if (_excludeChildrenOfPath.EndsWith("/*/")) { var itemParentPath = itemPath.Substring(0, itemPath.TrimEnd('/').LastIndexOf('/') + 1); // /foo/bar/ => /foo/ if (itemParentPath.Equals(wildcardFreePath, StringComparison.OrdinalIgnoreCase)) { return(new PredicateResult(true)); } } // the item is part of the exclusion return(new PredicateResult($"Children of {_excludeChildrenOfPath} excluded")); }
public ChildrenOfPathBasedPresetTreeExclusion(string excludeChildrenOfPath, ExceptionRule[] exceptions, PresetTreeRoot root) { _excludeChildrenOfPath = excludeChildrenOfPath; // path that does not start with / is relative to the parent include root path // eg include /foo, path 'bar' => /foo/bar if (!_excludeChildrenOfPath.StartsWith("/")) { _excludeChildrenOfPath = $"{root.Path.TrimEnd('/')}/{_excludeChildrenOfPath}"; } // normalize the root path to have a trailing slash which will make the path match only children // (like implicit matching) _excludeChildrenOfPath = PathTool.EnsureTrailingSlash(_excludeChildrenOfPath); // convert all exceptions to full paths with a trailing slash (so we can match on path segments) //_exceptions = exceptions.Select(exception => $"{PathTool.EnsureTrailingSlash(_excludeChildrenOfPath)}{exception}/").ToArray(); _exceptions = exceptions.Select(delegate(ExceptionRule exception) { var fullPath = $"{PathTool.EnsureTrailingSlash(_excludeChildrenOfPath)}{exception.Name}/"; return(Tuple.Create(fullPath, exception)); }).ToArray(); }
public PredicateResult Evaluate(IItemData itemData) { var itemPath = PathTool.EnsureTrailingSlash(itemData.Path); // you may preserve certain children from exclusion foreach (var exception in _exceptions) { var fullPath = exception.Item1; var exceptionRule = exception.Item2; var unescapedExceptionPath = fullPath.Replace(@"\*", "*"); if (exceptionRule.IncludeChildren) { if (itemPath.StartsWith(unescapedExceptionPath, StringComparison.OrdinalIgnoreCase)) { return(new PredicateResult(true)); } } else { if (itemPath.Equals(unescapedExceptionPath, StringComparison.OrdinalIgnoreCase)) { return(new PredicateResult(true)); } } } // if the path isn't under the exclusion, it's included var unescapedWildcardFreePath = _excludeChildrenOfPath.EndsWith("/*/") ? _excludeChildrenOfPath.Substring(0, _excludeChildrenOfPath.Length - 2) : _excludeChildrenOfPath; // unescape any "\*" escapes to match a literal wildcard item so we can compare the path (we don't check this variable for * later) unescapedWildcardFreePath = unescapedWildcardFreePath.Replace(@"\*", "*"); if (!itemPath.StartsWith(unescapedWildcardFreePath, StringComparison.OrdinalIgnoreCase)) { return(new PredicateResult(true)); } // if the path EQUALS the exclusion path it's included. Because we're including the root, and excluding the children. if (itemPath.Equals(unescapedWildcardFreePath, StringComparison.OrdinalIgnoreCase)) { return(new PredicateResult(true)); } // if the path EQUALS a wildcarded exclusion path it's included. // we accomplish this by doing an equals on the parent path of both the item path and the exclusion // /foo/bar => /foo, then match against COP = /foo/* => /foo/ == TRUE, so we include it // but, /foo/bar/baz => /foo/bar, match against COP /foo/* => /foo/ == FALSE, so it is excluded if (_excludeChildrenOfPath.EndsWith("/*/")) { var itemParentPath = itemPath.Substring(0, itemPath.TrimEnd('/').LastIndexOf('/') + 1); // /foo/bar/ => /foo/ if (itemParentPath.Equals(unescapedWildcardFreePath, StringComparison.OrdinalIgnoreCase)) { return(new PredicateResult(true)); } } // the item is part of the exclusion return(new PredicateResult($"Children of {_excludeChildrenOfPath} excluded")); }