private static string GetClassNameFromPath(string path)
        {
            const string cshtmlExtension = ".cshtml";

            if (string.IsNullOrEmpty(path))
            {
                return(path);
            }

            if (path.EndsWith(cshtmlExtension, StringComparison.OrdinalIgnoreCase))
            {
                path = path.Substring(0, path.Length - cshtmlExtension.Length);
            }

            return(CSharpIdentifier.SanitizeIdentifier(path));
        }
        // internal for testing.
        //
        // This code does a best-effort attempt to compute a namespace 'suffix' - the path difference between
        // where the @namespace directive appears and where the current document is on disk.
        //
        // In the event that these two source either don't have FileNames set or don't follow a coherent hierarchy,
        // we will just use the namespace verbatim.
        internal static string GetNamespace(string source, DirectiveIntermediateNode directive)
        {
            var directiveSource = NormalizeDirectory(directive.Source?.FilePath);

            var baseNamespace = directive.Tokens.FirstOrDefault()?.Content;

            if (string.IsNullOrEmpty(baseNamespace))
            {
                // The namespace directive was incomplete.
                return(string.Empty);
            }

            if (string.IsNullOrEmpty(source) || directiveSource == null)
            {
                // No sources, can't compute a suffix.
                return(baseNamespace);
            }

            // We're specifically using OrdinalIgnoreCase here because Razor treats all paths as case-insensitive.
            if (!source.StartsWith(directiveSource, StringComparison.OrdinalIgnoreCase) ||
                source.Length <= directiveSource.Length)
            {
                // The imports are not from the directory hierarchy, can't compute a suffix.
                return(baseNamespace);
            }

            // OK so that this point we know that the 'imports' file containing this directive is in the directory
            // hierarchy of this soure file. This is the case where we can append a suffix to the baseNamespace.
            //
            // Everything so far has just been defensiveness on our part.

            var builder = new StringBuilder(baseNamespace);

            var segments = source.Substring(directiveSource.Length).Split(Separators);

            // Skip the last segment because it's the FileName.
            for (var i = 0; i < segments.Length - 1; i++)
            {
                builder.Append('.');
                builder.Append(CSharpIdentifier.SanitizeIdentifier(segments[i]));
            }

            return(builder.ToString());
        }