public DirectoryMarkdownProcessor(
            string targetDirectory,
            AppendSnippetsToMarkdown appendSnippets,
            DocumentConvention convention = DocumentConvention.SourceTransform,
            bool scanForMdFiles           = true,
            bool scanForSnippets          = true,
            bool scanForIncludes          = true,
            Action <string>?log           = null,
            bool?writeHeader = null,
            string?header    = null,
            DirectoryFilter?directoryFilter = null,
            bool?readOnly = null,
            int tocLevel  = 2,
            IEnumerable <string>?tocExcludes        = null,
            IEnumerable <string>?documentExtensions = null,
            bool treatMissingAsWarning = false,
            int maxWidth            = int.MaxValue,
            bool validateContent    = false,
            string?newLine          = null,
            bool hashSnippetAnchors = false)
        {
            this.appendSnippets        = appendSnippets;
            this.convention            = convention;
            this.writeHeader           = writeHeader.GetValueOrDefault(convention == DocumentConvention.SourceTransform);
            this.readOnly              = readOnly.GetValueOrDefault(false);
            this.validateContent       = validateContent;
            this.header                = header;
            this.directoryFilter       = directoryFilter;
            this.tocLevel              = tocLevel;
            this.tocExcludes           = tocExcludes;
            this.documentExtensions    = MdFileFinder.BuildDefaultExtensions(documentExtensions);
            this.maxWidth              = maxWidth;
            this.treatMissingAsWarning = treatMissingAsWarning;

            this.log = log ?? (s => { Trace.WriteLine(s); });

            Guard.DirectoryExists(targetDirectory, nameof(targetDirectory));
            this.targetDirectory = Path.GetFullPath(targetDirectory);
            if (scanForMdFiles)
            {
                AddMdFilesFrom(targetDirectory);
            }

            this.newLine = FindNewLine(newLine);
            if (scanForSnippets)
            {
                AddSnippetsFrom(targetDirectory);
            }

            if (scanForIncludes)
            {
                AddIncludeFilesFrom(targetDirectory);
            }
        }
        public MarkdownProcessor(
            DocumentConvention convention,
            IReadOnlyDictionary <string, IReadOnlyList <Snippet> > snippets,
            IReadOnlyList <Include> includes,
            AppendSnippetsToMarkdown appendSnippets,
            IReadOnlyList <string> snippetSourceFiles,
            int tocLevel,
            bool writeHeader,
            string rootDirectory,
            bool validateContent,
            string?header = null,
            IEnumerable <string>?tocExcludes = null,
            string newLine = "\n")
        {
            Guard.AgainstNull(snippets, nameof(snippets));
            Guard.AgainstNull(appendSnippets, nameof(appendSnippets));
            Guard.AgainstNull(snippetSourceFiles, nameof(snippetSourceFiles));
            Guard.AgainstNull(includes, nameof(includes));
            Guard.AgainstNull(newLine, nameof(newLine));
            Guard.AgainstEmpty(header, nameof(header));
            Guard.AgainstNegativeAndZero(tocLevel, nameof(tocLevel));
            Guard.AgainstNullAndEmpty(rootDirectory, nameof(rootDirectory));

            if (convention == DocumentConvention.InPlaceOverwrite && writeHeader)
            {
                throw new SnippetException("WriteHeader is not allowed with InPlaceOverwrite convention.");
            }

            this.rootDirectory = Path.GetFullPath(rootDirectory).Replace('\\', '/');
            if (Directory.Exists(rootDirectory))
            {
                allFiles = Directory.EnumerateFiles(rootDirectory, "*.*", SearchOption.AllDirectories)
                           .Select(x => x.Replace('\\', '/'))
                           .ToList();
            }
            else
            {
                allFiles = new List <string>();
            }

            this.convention      = convention;
            this.snippets        = snippets;
            this.appendSnippets  = appendSnippets;
            this.writeHeader     = writeHeader;
            this.validateContent = validateContent;
            this.newLine         = newLine;
            this.header          = header;
            this.tocLevel        = tocLevel;
            if (tocExcludes == null)
            {
                this.tocExcludes = new List <string>();
            }
            else
            {
                this.tocExcludes = tocExcludes.ToList();
            }

            this.snippetSourceFiles = snippetSourceFiles
                                      .Select(x => x.Replace('\\', '/'))
                                      .ToList();
            includeProcessor = new IncludeProcessor(convention, includes, rootDirectory, allFiles);
        }