Minify <TResult>(string source, TResult space, TResult newLine, MinificationOptions options, Func <Token, TResult> resultSelector) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (resultSelector == null) { throw new ArgumentNullException(nameof(resultSelector)); } return(_()); IEnumerable <TResult> _() {
public static IEnumerable <string> Minify(string source, string newLine, MinificationOptions options) => Minify(source, " ", newLine, options, t => t.Substring(source));
public static IEnumerable <string> Minify(string source, MinificationOptions options) => Minify(source, Environment.NewLine, options);
public MinificationOptions OrCommentFilterOf(MinificationOptions other) => CommentFilter == other.CommentFilter || CommentFilter != null && other.CommentFilter == null ? this : CommentFilter == null && other.CommentFilter != null?WithCommentFilter(other.CommentFilter) : WithCommentFilter((t, s) => CommentFilter(t, s) || other.CommentFilter(t, s));
MinificationOptions(MinificationOptions options) : this(options.CommentFilter, options.KeepLeadComment) { }
Minify <TResult>(string source, TResult space, TResult newLine, MinificationOptions options, Func <Token, TResult> resultSelector) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (resultSelector == null) { throw new ArgumentNullException(nameof(resultSelector)); } return(_()); IEnumerable <TResult> _() { bool IsSpaceOrTab(char ch) => ch == ' ' || ch == '\t'; bool IsAsciiLetter(char ch) => (ch = (char)(ch & ~0x20)) >= 'A' && ch <= 'z'; bool IsWordChar(char ch) => char.IsLetter(ch) || ch >= '0' && ch <= '9' || ch == '_'; var lcs = LeadCommentState.Awaiting; var lastCh = (char?)null; var lastSingleLineCommentLine = (int?)null; TResult NewLineWhileResettingLastChar() { lastCh = null; return(newLine); } foreach (var t in Scanner.Scan(source)) { switch (t.Kind) { case TokenKind.NewLine: case TokenKind.WhiteSpace: break; case TokenKind k when k.HasTraits(TokenKindTraits.Comment) && options.KeepLeadComment && lcs != LeadCommentState.Processed && (lastSingleLineCommentLine is null || lastSingleLineCommentLine is int ln && t.Start.Line - ln == 1): { yield return(resultSelector(t)); if (k == TokenKind.SingleLineComment) { lastSingleLineCommentLine = t.Start.Line; yield return(NewLineWhileResettingLastChar()); lcs = LeadCommentState.Processing; } else { lcs = LeadCommentState.Processed; } break; } case TokenKind k when k.HasTraits(TokenKindTraits.Comment) && options.CommentFilter is Func <Token, string, bool> filter && filter(t, source): { yield return(resultSelector(t)); if (k == TokenKind.SingleLineComment) { yield return(NewLineWhileResettingLastChar()); } break; } case TokenKind k when k.HasTraits(TokenKindTraits.Comment): continue; default: { lcs = LeadCommentState.Processed; if (t.Kind == TokenKind.PreprocessorDirective) { var tei = t.End.Offset; var si = t.Start.Offset + 1; while (si < tei && IsSpaceOrTab(source[si])) { si++; } var ei = si; while (ei < tei && IsAsciiLetter(source[ei])) { ei++; } var length = ei - si; if (length == 0 || string.CompareOrdinal("region", 0, source, si, length) != 0 && string.CompareOrdinal("endregion", 0, source, si, length) != 0) { if (lastCh != null) { yield return(newLine); } yield return(resultSelector(t)); yield return(NewLineWhileResettingLastChar()); } } else { if (lastCh is char lch) { var ch = source[t.Start.Offset]; if (IsWordChar(ch) && IsWordChar(lch) || ch == lch && (ch == '+' || ch == '-' || ch == '*')) { yield return(space); } } yield return(resultSelector(t)); lastCh = source[t.End.Offset - 1]; } break; } } } } }