// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; namespace Microsoft.AspNetCore.Razor.Evolution { /// /// An abstraction for working with a project containing Razor files. /// public abstract class RazorProject { /// /// Gets a sequence of under the specific path in the project. /// /// The base path. /// The sequence of . public abstract IEnumerable EnumerateItems(string basePath); /// /// Gets a for the specified path. /// /// The path. /// The . public abstract RazorProjectItem GetItem(string path); /// /// Gets the sequence of files named that are applicable to the specified path. /// /// The path of a project item. /// The file name to seek. /// A sequence of applicable instances. /// /// This method returns paths starting from the directory of and /// traverses to the project root. /// e.g. /// /Views/Home/View.cshtml -> [ /Views/Home/FileName.cshtml, /Views/FileName.cshtml, /FileName.cshtml ] /// public virtual IEnumerable FindHierarchicalItems(string path, string fileName) { EnsureValidPath(path); if (string.IsNullOrEmpty(fileName)) { throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(fileName)); } Debug.Assert(!string.IsNullOrEmpty(path)); if (path.Length == 1) { yield break; } StringBuilder builder; var fileNameIndex = path.LastIndexOf('/'); var length = path.Length; Debug.Assert(fileNameIndex != -1); if (string.Compare(path, fileNameIndex + 1, fileName, 0, fileName.Length) == 0) { // If the specified path is for the file hierarchy being constructed, then the first file that applies // to it is in a parent directory. builder = new StringBuilder(path, 0, fileNameIndex, fileNameIndex + fileName.Length); length = fileNameIndex; } else { builder = new StringBuilder(path); } var index = length; while (index > 0 && (index = path.LastIndexOf('/', index - 1)) != -1) { builder.Length = index + 1; builder.Append(fileName); var itemPath = builder.ToString(); yield return GetItem(itemPath); } } /// /// Performs validation for paths passed to methods of . /// /// The path to validate. protected virtual void EnsureValidPath(string path) { if (string.IsNullOrEmpty(path)) { throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(path)); } if (path[0] != '/') { throw new ArgumentException(Resources.RazorProject_PathMustStartWithForwardSlash, nameof(path)); } } } }