AngleSharp by Florian Rappl

<PackageReference Include="AngleSharp" Version="0.8.7" />

 CssValueBuilder

sealed class CssValueBuilder
The class that is responsible for book-keeping information about the current CSS value that is been build.
using AngleSharp.Dom.Css; using System.Collections.Generic; using System.Diagnostics; namespace AngleSharp.Parser.Css { [DebuggerStepThrough] internal sealed class CssValueBuilder { private readonly List<CssToken> _values; private CssToken _buffer; private bool _valid; private bool _important; private int _open; public bool IsReady { get { if (_open == 0) return _values.Count > 0; return false; } } public CssValue Result { get { if (!IsValid) return null; return new CssValue(_values); } } public bool IsValid { get { if (_valid) return IsReady; return false; } } public bool IsImportant => _important; public CssValueBuilder() { _values = new List<CssToken>(); Reset(); } public void Apply(CssToken token) { switch (token.Type) { case CssTokenType.RoundBracketOpen: _open++; Add(token); break; case CssTokenType.Function: Add(token); break; case CssTokenType.Ident: _important = CheckImportant(token); break; case CssTokenType.RoundBracketClose: _open--; Add(token); break; case CssTokenType.Whitespace: if (_values.Count > 0 && !IsSlash(_values[_values.Count - 1])) _buffer = token; break; case CssTokenType.String: case CssTokenType.Url: case CssTokenType.Color: case CssTokenType.Number: case CssTokenType.Percentage: case CssTokenType.Dimension: case CssTokenType.Delim: case CssTokenType.Comma: Add(token); break; default: _valid = false; break; } } public CssValueBuilder Reset() { _open = 0; _valid = true; _buffer = null; _important = false; _values.Clear(); return this; } private bool CheckImportant(CssToken token) { if (_values.Count != 0 && token.Data == Keywords.Important) { CssToken token2 = _values[_values.Count - 1]; if (IsExclamationMark(token2)) { do { _values.RemoveAt(_values.Count - 1); } while (_values.Count > 0 && _values[_values.Count - 1].Type == CssTokenType.Whitespace); return true; } } Add(token); return _important; } private void Add(CssToken token) { if (_buffer != null && !IsCommaOrSlash(token)) _values.Add(_buffer); else if (_values.Count != 0 && !IsComma(token) && IsComma(_values[_values.Count - 1])) { _values.Add(CssToken.Whitespace); } _buffer = null; if (_important) _valid = false; else if (_valid) { _values.Add(token); } } private static bool IsCommaOrSlash(CssToken token) { if (!IsComma(token)) return IsSlash(token); return true; } private static bool IsComma(CssToken token) { return token.Type == CssTokenType.Comma; } private static bool IsExclamationMark(CssToken token) { if (token.Type == CssTokenType.Delim) return token.Data[0] == '!'; return false; } private static bool IsSlash(CssToken token) { if (token.Type == CssTokenType.Delim) return token.Data[0] == '/'; return false; } } }