diff --git a/src/DocNet/Config.cs b/src/DocNet/Config.cs index be71b36..f67046f 100644 --- a/src/DocNet/Config.cs +++ b/src/DocNet/Config.cs @@ -307,6 +307,25 @@ namespace Docnet } } + public UrlFormatting UrlFormatting + { + get + { + var urlFormatting = UrlFormatting.None; + + var urlFormattingAsString = (string)_configData.UrlFormatting; + if (!string.IsNullOrWhiteSpace(urlFormattingAsString)) + { + if (!Enum.TryParse(urlFormattingAsString, true, out urlFormatting)) + { + urlFormatting = UrlFormatting.None; + } + } + + return urlFormatting; + } + } + public NavigationLevel Pages { get diff --git a/src/DocNet/Docnet.csproj b/src/DocNet/Docnet.csproj index b2d7f24..b47e767 100644 --- a/src/DocNet/Docnet.csproj +++ b/src/DocNet/Docnet.csproj @@ -68,6 +68,8 @@ + + diff --git a/src/DocNet/Engine.cs b/src/DocNet/Engine.cs index 6cffe93..1dff26a 100644 --- a/src/DocNet/Engine.cs +++ b/src/DocNet/Engine.cs @@ -45,12 +45,8 @@ namespace Docnet return 1; } - var navigationContext = new NavigationContext - { - MaxLevel = _loadedConfig.MaxLevelInToC, - PathSpecification = _loadedConfig.PathSpecification, - StripIndexHtm = _loadedConfig.StripIndexHtm - }; + var navigationContext = new NavigationContext(_loadedConfig.PathSpecification, _loadedConfig.UrlFormatting, + _loadedConfig.MaxLevelInToC, _loadedConfig.StripIndexHtm); GeneratePages(navigationContext); return 0; @@ -79,7 +75,8 @@ namespace Docnet return null; } - var navigationContext = new NavigationContext(config.PathSpecification, config.MaxLevelInToC, config.StripIndexHtm); + var navigationContext = new NavigationContext(config.PathSpecification, config.UrlFormatting, + config.MaxLevelInToC, config.StripIndexHtm); var indexElement = config.Pages.GetIndexElement(navigationContext); if(indexElement == null) diff --git a/src/DocNet/NavigationContext.cs b/src/DocNet/NavigationContext.cs index b2e4dfb..33c891f 100644 --- a/src/DocNet/NavigationContext.cs +++ b/src/DocNet/NavigationContext.cs @@ -7,17 +7,20 @@ MaxLevel = 2; } - public NavigationContext(PathSpecification pathSpecification, int maxLevel, bool stripIndexHtm) + public NavigationContext(PathSpecification pathSpecification, UrlFormatting urlFormatting, int maxLevel, bool stripIndexHtm) : this() { PathSpecification = pathSpecification; - MaxLevel = maxLevel; + UrlFormatting = urlFormatting; + MaxLevel = maxLevel; StripIndexHtm = stripIndexHtm; } public PathSpecification PathSpecification { get; set; } - public int MaxLevel { get; set; } + public UrlFormatting UrlFormatting { get; set; } + + public int MaxLevel { get; set; } public bool StripIndexHtm { get; set; } } diff --git a/src/DocNet/NavigationLevel.cs b/src/DocNet/NavigationLevel.cs index 9b30cff..73f2021 100644 --- a/src/DocNet/NavigationLevel.cs +++ b/src/DocNet/NavigationLevel.cs @@ -305,7 +305,20 @@ namespace Docnet } } - var nameToUse = this.Name.Replace(".", "").Replace('/', '_').Replace("\\", "_").Replace(":", "").Replace(" ", ""); + var nameToUse = string.Empty; + + switch (navigationContext.UrlFormatting) + { + case UrlFormatting.None: + // Backwards compatibility mode + nameToUse = this.Name.Replace(".", "").Replace('/', '_').Replace("\\", "_").Replace(":", "").Replace(" ", ""); + break; + + default: + nameToUse = this.Name.ApplyUrlFormatting(navigationContext.UrlFormatting); + break; + } + if (string.IsNullOrWhiteSpace(nameToUse)) { return null; diff --git a/src/DocNet/SimpleNavigationElement.cs b/src/DocNet/SimpleNavigationElement.cs index 55ad6df..e8722db 100644 --- a/src/DocNet/SimpleNavigationElement.cs +++ b/src/DocNet/SimpleNavigationElement.cs @@ -226,14 +226,18 @@ namespace Docnet { if (_targetURLForHTML == null) { - _targetURLForHTML = (this.Value ?? string.Empty); - - var toReplace = ".md"; + var toReplace = "mdext"; var replacement = ".htm"; + var value = (this.Value ?? string.Empty); + + // Replace with custom extension because url formatting might optimize the extension + value = value.Replace(".md", toReplace); + _targetURLForHTML = value.ApplyUrlFormatting(navigationContext.UrlFormatting); + if (navigationContext.PathSpecification == PathSpecification.RelativeAsFolder) { - if (!IsIndexElement && !_targetURLForHTML.EndsWith("index.md", StringComparison.InvariantCultureIgnoreCase)) + if (!IsIndexElement && !_targetURLForHTML.EndsWith($"index{toReplace}", StringComparison.InvariantCultureIgnoreCase)) { replacement = "/index.htm"; } diff --git a/src/DocNet/StringExtensions.cs b/src/DocNet/StringExtensions.cs new file mode 100644 index 0000000..ebf2c41 --- /dev/null +++ b/src/DocNet/StringExtensions.cs @@ -0,0 +1,61 @@ +using System; +using System.Text.RegularExpressions; + +namespace Docnet +{ + internal static class StringExtensions + { + public static string ApplyUrlFormatting(this string value, UrlFormatting urlFormatting) + { + var finalValue = string.Empty; + string replacementValue = null; + + switch (urlFormatting) + { + case UrlFormatting.None: + finalValue = value; + break; + + case UrlFormatting.Strip: + replacementValue = string.Empty; + break; + + case UrlFormatting.Dashes: + replacementValue = "-"; + break; + + default: + throw new ArgumentOutOfRangeException(nameof(urlFormatting), urlFormatting, null); + } + + var splitted = value.Split(new[] { "/", "\\" }, StringSplitOptions.RemoveEmptyEntries); + + if (replacementValue != null) + { + var doubleReplacementValue = replacementValue + replacementValue; + var regEx = new Regex("[^a-zA-Z0-9 -]"); + + for (var i = 0; i < splitted.Length; i++) + { + var splittedValue = splitted[i]; + + splittedValue = regEx.Replace(splittedValue, replacementValue).Replace(" ", replacementValue); + + if (!string.IsNullOrEmpty(replacementValue)) + { + while (splittedValue.Contains(doubleReplacementValue)) + { + splittedValue = splittedValue.Replace(doubleReplacementValue, replacementValue); + } + } + + splitted[i] = splittedValue.ToLower(); + } + + finalValue = string.Join("/", splitted); + } + + return finalValue; + } + } +} \ No newline at end of file diff --git a/src/DocNet/UrlFormatting.cs b/src/DocNet/UrlFormatting.cs new file mode 100644 index 0000000..7937bb1 --- /dev/null +++ b/src/DocNet/UrlFormatting.cs @@ -0,0 +1,11 @@ +namespace Docnet +{ + public enum UrlFormatting + { + None, + + Strip, + + Dashes + } +} \ No newline at end of file