Пример #1
0
 public CssNode(CssNodeType type, CssNode parent, string text)
 {
     Type        = type;
     Parent      = parent;
     TextBuilder = new StringBuilder(text);
 }
Пример #2
0
        internal static CssNode GetAst(string cssDocument)
        {
            var doc = new CssNode(CssNodeType.Document, null, "");

            var currentNode = doc;

            var tokens = Tokenize(cssDocument).ToList();

            for (var i = 0; i < tokens.Count;)
            {
                var t = tokens[i++];

                CssNode n;

                switch (t.Type)
                {
                case CssTokenType.At:

                    if (currentNode.Type == CssNodeType.Document)
                    {
                        n = new CssNode(CssNodeType.NamespaceDeclaration, currentNode, "");
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.DoubleQuoteText ||
                             currentNode.Type == CssNodeType.SingleQuoteText)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    break;

                case CssTokenType.Identifier:
                    if (currentNode.Type == CssNodeType.NamespaceDeclaration)
                    {
                        n = new CssNode(CssNodeType.NamespaceKeyword, currentNode, "@" + t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceKeyword)
                    {
                        currentNode = currentNode.Parent;
                        n           = new CssNode(CssNodeType.NamespaceAlias, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceValue)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.Selectors)
                    {
                        n = new CssNode(CssNodeType.Selector, currentNode, "");
                        currentNode.Children.Add(n);
                        var fragment = new CssNode(CssNodeType.SelectorFragment, n, t.Text);
                        n.Children.Add(fragment);
                        currentNode = fragment;
                    }
                    else if (currentNode.Type == CssNodeType.Selector)
                    {
                        n = new CssNode(CssNodeType.SelectorFragment, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.SelectorFragment)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.StyleDeclarationBlock)
                    {
                        n = new CssNode(CssNodeType.StyleDeclaration, currentNode, "");
                        currentNode.Children.Add(n);
                        currentNode = n;

                        n = new CssNode(CssNodeType.Key, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.StyleDeclaration)
                    {
                        n = new CssNode(CssNodeType.Value, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.Key)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.Value)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.Document)
                    {
                        n = new CssNode(CssNodeType.StyleRule, currentNode, "");
                        var selectors = new CssNode(CssNodeType.Selectors, n, "");
                        n.Children.Add(selectors);

                        currentNode.Children.Add(n);
                        currentNode = selectors;

                        var selector = new CssNode(CssNodeType.Selector, currentNode, "");
                        currentNode.Children.Add(selector);
                        currentNode = selector;

                        var selectorFragment = new CssNode(CssNodeType.SelectorFragment, currentNode, t.Text);
                        currentNode.Children.Add(selectorFragment);
                        currentNode = selectorFragment;
                    }
                    if (currentNode.Type == CssNodeType.DoubleQuoteText ||
                        currentNode.Type == CssNodeType.SingleQuoteText)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    break;

                case CssTokenType.DoubleQuotes:
                    if (currentNode.Type == CssNodeType.NamespaceKeyword)
                    {
                        currentNode = currentNode.Parent;
                        currentNode.Children.Add(new CssNode(CssNodeType.NamespaceAlias, currentNode, ""));
                        n = new CssNode(CssNodeType.NamespaceValue, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceAlias)
                    {
                        currentNode = currentNode.Parent;
                        n           = new CssNode(CssNodeType.NamespaceValue, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceValue)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.StyleDeclaration)
                    {
                        n = new CssNode(CssNodeType.Value, currentNode, "");
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.Key)
                    {
                        n = new CssNode(CssNodeType.Value, currentNode.Parent, "");
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    if (currentNode.Type == CssNodeType.Value)
                    {
                        n = new CssNode(CssNodeType.DoubleQuoteText, currentNode, "");
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.DoubleQuoteText)
                    {
                        currentNode = currentNode.Parent;
                    }
                    break;

                case CssTokenType.SingleQuotes:
                    if (currentNode.Type == CssNodeType.StyleDeclaration)
                    {
                        n = new CssNode(CssNodeType.Value, currentNode, "");
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.Key)
                    {
                        n = new CssNode(CssNodeType.Value, currentNode.Parent, "");
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    if (currentNode.Type == CssNodeType.Value)
                    {
                        n = new CssNode(CssNodeType.SingleQuoteText, currentNode, "");
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.SingleQuoteText)
                    {
                        currentNode = currentNode.Parent;
                    }
                    break;

                case CssTokenType.Colon:
                    if (currentNode.Type == CssNodeType.Key)
                    {
                        currentNode = currentNode.Parent;
                    }
                    else if (currentNode.Type == CssNodeType.SelectorFragment)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.Value)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.DoubleQuoteText ||
                             currentNode.Type == CssNodeType.SingleQuoteText)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    break;

                case CssTokenType.Semicolon:
                    if (currentNode.Type == CssNodeType.Value)
                    {
                        currentNode = currentNode.Parent;
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceValue)
                    {
                        currentNode = currentNode.Parent;
                    }
                    else if (currentNode.Type == CssNodeType.DoubleQuoteText ||
                             currentNode.Type == CssNodeType.SingleQuoteText)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    currentNode = currentNode.Parent;
                    break;

                case CssTokenType.Dot:
                    if (currentNode.Type == CssNodeType.Document)
                    {
                        n = new CssNode(CssNodeType.StyleRule, currentNode, "");
                        var selectors = new CssNode(CssNodeType.Selectors, n, "");
                        n.Children.Add(selectors);

                        currentNode.Children.Add(n);
                        currentNode = selectors;

                        var selector = new CssNode(CssNodeType.Selector, currentNode, "");
                        currentNode.Children.Add(selector);
                        currentNode = selector;

                        var selectorFragment = new CssNode(CssNodeType.SelectorFragment, currentNode, t.Text);
                        currentNode.Children.Add(selectorFragment);
                        currentNode = selectorFragment;
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceAlias)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceValue)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.Selectors)
                    {
                        var selector = new CssNode(CssNodeType.Selector, currentNode, "");
                        currentNode.Children.Add(selector);
                        currentNode = selector;
                        currentNode.Children.Add(new CssNode(CssNodeType.SelectorFragment, currentNode, "." + tokens[i++].Text));
                    }
                    else if (currentNode.Type == CssNodeType.Selector)
                    {
                        var selectorFragment = new CssNode(CssNodeType.SelectorFragment, currentNode, ".");
                        currentNode.Children.Add(selectorFragment);
                        currentNode = selectorFragment;
                    }
                    else if (currentNode.Type == CssNodeType.SelectorFragment)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.Key)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.DoubleQuoteText ||
                             currentNode.Type == CssNodeType.SingleQuoteText)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    break;

                case CssTokenType.Hash:
                    if (currentNode.Type == CssNodeType.Document)
                    {
                        n = new CssNode(CssNodeType.StyleRule, currentNode, "");
                        var selectors = new CssNode(CssNodeType.Selectors, n, "");
                        n.Children.Add(selectors);

                        currentNode.Children.Add(n);
                        currentNode = selectors;

                        var selector = new CssNode(CssNodeType.Selector, currentNode, "");
                        currentNode.Children.Add(selector);
                        currentNode = selector;

                        var selectorFragment = new CssNode(CssNodeType.SelectorFragment, currentNode, t.Text);
                        currentNode.Children.Add(selectorFragment);
                        currentNode = selectorFragment;
                    }
                    else if (currentNode.Type == CssNodeType.Selectors)
                    {
                        var selector = new CssNode(CssNodeType.Selector, currentNode, "");
                        currentNode.Children.Add(selector);
                        currentNode = selector;
                        var selectorFragment = new CssNode(CssNodeType.SelectorFragment, currentNode, t.Text);
                        currentNode.Children.Add(selectorFragment);
                        currentNode = selectorFragment;
                    }
                    else if (currentNode.Type == CssNodeType.Selector)
                    {
                        var selectorFragment = new CssNode(CssNodeType.SelectorFragment, currentNode, ".");
                        currentNode.Children.Add(selectorFragment);
                        currentNode = selectorFragment;
                    }
                    else if (currentNode.Type == CssNodeType.SelectorFragment)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.StyleDeclaration)
                    {
                        n = new CssNode(CssNodeType.Value, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.DoubleQuoteText ||
                             currentNode.Type == CssNodeType.SingleQuoteText)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    break;

                case CssTokenType.AngleBraketClose:
                    if (currentNode.Type == CssNodeType.SelectorFragment)
                    {
                        currentNode = currentNode.Parent;
                    }
                    if (currentNode.Type == CssNodeType.Selector)
                    {
                        currentNode.Children.Add(new CssNode(CssNodeType.SelectorFragment, currentNode, ">"));
                    }
                    else if (currentNode.Type == CssNodeType.DoubleQuoteText ||
                             currentNode.Type == CssNodeType.SingleQuoteText)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    break;

                case CssTokenType.ParenthesisOpen:
                case CssTokenType.ParenthesisClose:
                    if (currentNode.Type == CssNodeType.Value)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.SelectorFragment)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.DoubleQuoteText ||
                             currentNode.Type == CssNodeType.SingleQuoteText)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    break;

                case CssTokenType.Comma:
                    if (currentNode.Type == CssNodeType.SelectorFragment)
                    {
                        currentNode = currentNode.Parent;
                    }
                    if (currentNode.Type == CssNodeType.Selector)
                    {
                        currentNode = currentNode.Parent;
                    }
                    if (currentNode.Type == CssNodeType.Value)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceValue)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.DoubleQuoteText ||
                             currentNode.Type == CssNodeType.SingleQuoteText)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    break;

                case CssTokenType.Pipe:
                    if (currentNode.Type == CssNodeType.SelectorFragment)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.Key)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.DoubleQuoteText ||
                             currentNode.Type == CssNodeType.SingleQuoteText)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    break;

                case CssTokenType.BraceOpen:
                    currentNode.Text = new StringBuilder(currentNode.Text.ToString().Trim());
                    if (currentNode.Type == CssNodeType.StyleDeclaration)
                    {
                        n = new CssNode(CssNodeType.Value, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.DoubleQuoteText ||
                             currentNode.Type == CssNodeType.SingleQuoteText)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else
                    {
                        if (currentNode.Type == CssNodeType.SelectorFragment)
                        {
                            currentNode = currentNode.Parent;
                        }
                        if (currentNode.Type == CssNodeType.Selector)
                        {
                            currentNode = currentNode.Parent;
                        }
                        if (currentNode.Type == CssNodeType.Selectors)
                        {
                            currentNode = currentNode.Parent;
                        }
                        n = new CssNode(CssNodeType.StyleDeclarationBlock, currentNode, "");
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    break;

                case CssTokenType.BraceClose:
                    if (currentNode.Type == CssNodeType.Value)
                    {
                        currentNode.Text.Append(t.Text);
                        currentNode = currentNode.Parent;
                    }
                    else if (currentNode.Type == CssNodeType.DoubleQuoteText ||
                             currentNode.Type == CssNodeType.SingleQuoteText)
                    {
                        currentNode.Text.Append(t.Text);
                    }
                    else
                    {
                        currentNode = currentNode.Parent.Parent;
                    }
                    break;

                case CssTokenType.Whitespace:
                    currentNode.Text.Append(t.Text);
                    break;
                }
            }

            return(doc);
        }
Пример #3
0
 private static List <string> GetSelectorStringsFromSelectorsCssNode(CssNode selectors)
 {
     return(selectors.Children
            .Select(x => string.Join(" ", x.Children /* selector-fragment */.Select(y => y.Text)))
            .ToList());
 }
Пример #4
0
        internal static CssNode GetAst(string cssDocument)
        {
            var doc = new CssNode(CssNodeType.Document, null, "");

            var currentNode = doc;

            var tokens = Tokenizer.Tokenize(cssDocument).ToList();

            for (var i = 0; i < tokens.Count; i++)
            {
                var t = tokens[i];

                CssNode n;

                switch (t.Type)
                {
                case CssTokenType.At:
                    if (currentNode.Type == CssNodeType.Document)
                    {
                        n = new CssNode(CssNodeType.NamespaceDeclaration, currentNode, "");
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.Value ||
                             currentNode.Type == CssNodeType.VariableValue)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    break;

                case CssTokenType.Dollar:
                    if (currentNode.Type == CssNodeType.Document ||
                        currentNode.Type == CssNodeType.StyleDeclarationBlock)
                    {
                        n = new CssNode(CssNodeType.VariableDeclaration, currentNode, "");
                        currentNode.Children.Add(n);
                        currentNode = n;

                        n = new CssNode(CssNodeType.VariableName, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.Value)
                    {
                        n = new CssNode(CssNodeType.VariableReference, currentNode, "$");
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    break;

                case CssTokenType.Identifier:
                    if (currentNode.Type == CssNodeType.VariableName)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.VariableValue)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.VariableReference)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceDeclaration)
                    {
                        n = new CssNode(CssNodeType.NamespaceKeyword, currentNode, "@" + t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceKeyword)
                    {
                        currentNode = currentNode.Parent;
                        n           = new CssNode(CssNodeType.NamespaceAlias, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceValue)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.Selectors)
                    {
                        n = new CssNode(CssNodeType.Selector, currentNode, "");
                        currentNode.Children.Add(n);
                        var fragment = new CssNode(CssNodeType.SelectorFragment, n, t.Text);
                        n.Children.Add(fragment);
                        currentNode = fragment;
                    }
                    else if (currentNode.Type == CssNodeType.Selector)
                    {
                        n = new CssNode(CssNodeType.SelectorFragment, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.SelectorFragment)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.StyleDeclarationBlock)
                    {
                        n = new CssNode(CssNodeType.StyleDeclaration, currentNode, "");
                        currentNode.Children.Add(n);
                        currentNode = n;

                        n = new CssNode(CssNodeType.Key, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.StyleDeclaration)
                    {
                        n = new CssNode(CssNodeType.Value, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.Key)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.Value)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.Document)
                    {
                        n = new CssNode(CssNodeType.StyleRule, currentNode, "");
                        var selectors = new CssNode(CssNodeType.Selectors, n, "");
                        n.Children.Add(selectors);

                        currentNode.Children.Add(n);
                        currentNode = selectors;

                        var selector = new CssNode(CssNodeType.Selector, currentNode, "");
                        currentNode.Children.Add(selector);
                        currentNode = selector;

                        var selectorFragment = new CssNode(CssNodeType.SelectorFragment, currentNode, t.Text);
                        currentNode.Children.Add(selectorFragment);
                        currentNode = selectorFragment;
                    }
                    break;

                case CssTokenType.DoubleQuotes:
                    if (currentNode.Type == CssNodeType.NamespaceKeyword)
                    {
                        currentNode = currentNode.Parent;
                        currentNode.Children.Add(new CssNode(CssNodeType.NamespaceAlias, currentNode, ""));
                        n = new CssNode(CssNodeType.NamespaceValue, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceAlias)
                    {
                        currentNode = currentNode.Parent;
                        n           = new CssNode(CssNodeType.NamespaceValue, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceValue)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.StyleDeclaration)
                    {
                        n = new CssNode(CssNodeType.Value, currentNode, "");
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.Key)
                    {
                        n = new CssNode(CssNodeType.Value, currentNode.Parent, "");
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    if (currentNode.Type == CssNodeType.Value)
                    {
                        n = new CssNode(CssNodeType.DoubleQuoteText, currentNode, "");
                        currentNode.Children.Add(n);
                        currentNode = n;

                        i++;
                        do
                        {
                            if (tokens[i].Type == CssTokenType.Backslash)
                            {
                                i++;
                                currentNode.TextBuilder.Append(tokens[i].Text);
                            }
                            else if (tokens[i].Type == CssTokenType.DoubleQuotes)
                            {
                                currentNode = currentNode.Parent;
                                break;
                            }
                            else
                            {
                                currentNode.TextBuilder.Append(tokens[i].Text);
                            }
                            i++;
                        } while (i < tokens.Count);
                    }
                    else if (currentNode.Type == CssNodeType.VariableValue)
                    {
                        i++;
                        do
                        {
                            if (tokens[i].Type == CssTokenType.Backslash)
                            {
                                i++;
                                currentNode.TextBuilder.Append(tokens[i].Text);
                            }
                            else if (tokens[i].Type == CssTokenType.DoubleQuotes)
                            {
                                currentNode = currentNode.Parent;
                                break;
                            }
                            else
                            {
                                currentNode.TextBuilder.Append(tokens[i].Text);
                            }
                            i++;
                        } while (i < tokens.Count);
                    }
                    else if (currentNode.Type == CssNodeType.DoubleQuoteText)
                    {
                        currentNode = currentNode.Parent;
                    }
                    break;

                case CssTokenType.SingleQuotes:
                    if (currentNode.Type == CssNodeType.StyleDeclaration)
                    {
                        n = new CssNode(CssNodeType.Value, currentNode, "");
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.Key)
                    {
                        n = new CssNode(CssNodeType.Value, currentNode.Parent, "");
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    if (currentNode.Type == CssNodeType.Value)
                    {
                        n = new CssNode(CssNodeType.SingleQuoteText, currentNode, "");
                        currentNode.Children.Add(n);
                        currentNode = n;
                        i++;

                        do
                        {
                            if (tokens[i].Type == CssTokenType.Backslash)
                            {
                                i++;
                                currentNode.TextBuilder.Append(tokens[i].Text);
                            }
                            else if (tokens[i].Type == CssTokenType.SingleQuotes)
                            {
                                currentNode = currentNode.Parent;
                                break;
                            }
                            else
                            {
                                currentNode.TextBuilder.Append(tokens[i].Text);
                            }
                            i++;
                        } while (i < tokens.Count);
                    }
                    else if (currentNode.Type == CssNodeType.SingleQuoteText)
                    {
                        currentNode = currentNode.Parent;
                    }
                    break;

                case CssTokenType.Colon:
                    if (currentNode.Type == CssNodeType.VariableName)
                    {
                        currentNode = currentNode.Parent;

                        n = new CssNode(CssNodeType.VariableValue, currentNode, "");
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.Key)
                    {
                        var nextToken = FirstTokenTypeOf(tokens, i, new[] { CssTokenType.Semicolon, CssTokenType.DoubleQuotes, CssTokenType.BraceOpen });

                        // normal value
                        if (nextToken == CssTokenType.Semicolon ||
                            nextToken == CssTokenType.DoubleQuotes)
                        {
                            currentNode = currentNode.Parent;

                            n = new CssNode(CssNodeType.Value, currentNode, "");
                            currentNode.Children.Add(n);
                            currentNode = n;

                            i++;
                            while (t.Type == CssTokenType.Whitespace)
                            {
                                i++;
                                t = tokens[i];
                            }
                        }
                        else     // selector
                        {
                            currentNode.TextBuilder.Append(t.Text);
                        }
                    }
                    else if (currentNode.Type == CssNodeType.SelectorFragment)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.Value)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    break;

                case CssTokenType.Semicolon:
                    if (currentNode.Type == CssNodeType.VariableReference)
                    {
                        currentNode = currentNode.Parent;
                    }
                    if (currentNode.Type == CssNodeType.Value)
                    {
                        currentNode = currentNode.Parent;
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceValue)
                    {
                        currentNode = currentNode.Parent;
                    }
                    else if (currentNode.Type == CssNodeType.VariableValue)
                    {
                        currentNode = currentNode.Parent;
                    }
                    currentNode = currentNode.Parent;
                    break;

                case CssTokenType.Dot:
                    if (currentNode.Type == CssNodeType.Document ||
                        currentNode.Type == CssNodeType.StyleDeclarationBlock)
                    {
                        n = new CssNode(CssNodeType.StyleRule, currentNode, "");
                        var selectors = new CssNode(CssNodeType.Selectors, n, "");
                        n.Children.Add(selectors);

                        currentNode.Children.Add(n);
                        currentNode = selectors;

                        var selector = new CssNode(CssNodeType.Selector, currentNode, "");
                        currentNode.Children.Add(selector);
                        currentNode = selector;

                        var selectorFragment = new CssNode(CssNodeType.SelectorFragment, currentNode, t.Text);
                        currentNode.Children.Add(selectorFragment);
                        currentNode = selectorFragment;
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceAlias)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceValue)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.Selectors)
                    {
                        var selector = new CssNode(CssNodeType.Selector, currentNode, "");
                        currentNode.Children.Add(selector);

                        var selectorFragment = new CssNode(CssNodeType.SelectorFragment, selector, tokens[i].Text);
                        selector.Children.Add(selectorFragment);

                        currentNode = selectorFragment;
                    }
                    else if (currentNode.Type == CssNodeType.Selector)
                    {
                        var selectorFragment = new CssNode(CssNodeType.SelectorFragment, currentNode, ".");
                        currentNode.Children.Add(selectorFragment);
                        currentNode = selectorFragment;
                    }
                    else if (currentNode.Type == CssNodeType.SelectorFragment)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.Key)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.Value)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    break;

                case CssTokenType.Hash:
                    if (currentNode.Type == CssNodeType.Document)
                    {
                        n = new CssNode(CssNodeType.StyleRule, currentNode, "");
                        var selectors = new CssNode(CssNodeType.Selectors, n, "");
                        n.Children.Add(selectors);

                        currentNode.Children.Add(n);
                        currentNode = selectors;

                        var selector = new CssNode(CssNodeType.Selector, currentNode, "");
                        currentNode.Children.Add(selector);
                        currentNode = selector;

                        var selectorFragment = new CssNode(CssNodeType.SelectorFragment, currentNode, t.Text);
                        currentNode.Children.Add(selectorFragment);
                        currentNode = selectorFragment;
                    }
                    else if (currentNode.Type == CssNodeType.Selectors)
                    {
                        var selector = new CssNode(CssNodeType.Selector, currentNode, "");
                        currentNode.Children.Add(selector);
                        currentNode = selector;
                        var selectorFragment = new CssNode(CssNodeType.SelectorFragment, currentNode, t.Text);
                        currentNode.Children.Add(selectorFragment);
                        currentNode = selectorFragment;
                    }
                    else if (currentNode.Type == CssNodeType.Selector)
                    {
                        var selectorFragment = new CssNode(CssNodeType.SelectorFragment, currentNode, ".");
                        currentNode.Children.Add(selectorFragment);
                        currentNode = selectorFragment;
                    }
                    else if (currentNode.Type == CssNodeType.SelectorFragment)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.StyleDeclaration)
                    {
                        n = new CssNode(CssNodeType.Value, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.Value)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.VariableValue)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    break;

                case CssTokenType.AngleBraketClose:
                    if (currentNode.Type == CssNodeType.SelectorFragment)
                    {
                        currentNode = currentNode.Parent;
                    }
                    if (currentNode.Type == CssNodeType.Selector)
                    {
                        currentNode.Children.Add(new CssNode(CssNodeType.SelectorFragment, currentNode, ">"));
                    }
                    break;

                case CssTokenType.ParenthesisOpen:
                case CssTokenType.ParenthesisClose:
                    if (currentNode.Type == CssNodeType.Value)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.Key)     // selector
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.SelectorFragment)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    break;

                case CssTokenType.Comma:
                    if (currentNode.Type == CssNodeType.Key)
                    {
                        var keyValue = currentNode.Text;

                        var styleDeclaration = currentNode.Parent;
                        styleDeclaration.Children.Remove(currentNode);

                        var subRule = styleDeclaration;
                        subRule.Type = CssNodeType.StyleRule;

                        var selectors = new CssNode(CssNodeType.Selectors, subRule, "");
                        subRule.Children.Add(selectors);

                        currentNode = selectors;

                        var selector = new CssNode(CssNodeType.Selector, currentNode, "");
                        currentNode.Children.Add(selector);
                        currentNode = selector;

                        var selectorFragment = new CssNode(CssNodeType.SelectorFragment, currentNode, keyValue);
                        currentNode.Children.Add(selectorFragment);
                        currentNode = selectorFragment;
                    }
                    if (currentNode.Type == CssNodeType.SelectorFragment)
                    {
                        currentNode = currentNode.Parent;
                    }
                    if (currentNode.Type == CssNodeType.Selector)
                    {
                        currentNode = currentNode.Parent;
                    }
                    if (currentNode.Type == CssNodeType.Value)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.NamespaceValue)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    break;

                case CssTokenType.Pipe:
                    if (currentNode.Type == CssNodeType.SelectorFragment)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else if (currentNode.Type == CssNodeType.Key)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    break;

                case CssTokenType.BraceOpen:

                    if (currentNode.Type == CssNodeType.Key)
                    {
                        var keyValue = currentNode.Text;

                        var styleDeclaration = currentNode.Parent;
                        styleDeclaration.Children.Remove(currentNode);

                        var subRule = styleDeclaration;
                        subRule.Type = CssNodeType.StyleRule;

                        var selectors = new CssNode(CssNodeType.Selectors, subRule, "");
                        subRule.Children.Add(selectors);

                        currentNode = selectors;

                        var selector = new CssNode(CssNodeType.Selector, currentNode, "");
                        currentNode.Children.Add(selector);
                        currentNode = selector;

                        var selectorFragment = new CssNode(CssNodeType.SelectorFragment, currentNode, keyValue);
                        currentNode.Children.Add(selectorFragment);
                        currentNode = selectorFragment;
                    }

                    currentNode.TextBuilder = new StringBuilder(currentNode.TextBuilder.ToString().Trim());
                    if (currentNode.Type == CssNodeType.StyleDeclaration)
                    {
                        n = new CssNode(CssNodeType.Value, currentNode, t.Text);
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    else if (currentNode.Type == CssNodeType.Value)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                    }
                    else
                    {
                        if (currentNode.Type == CssNodeType.SelectorFragment)
                        {
                            currentNode = currentNode.Parent;
                        }
                        if (currentNode.Type == CssNodeType.Selector)
                        {
                            currentNode = currentNode.Parent;
                        }
                        if (currentNode.Type == CssNodeType.Selectors)
                        {
                            currentNode = currentNode.Parent;
                        }
                        n = new CssNode(CssNodeType.StyleDeclarationBlock, currentNode, "");
                        currentNode.Children.Add(n);
                        currentNode = n;
                    }
                    break;

                case CssTokenType.BraceClose:
                    if (currentNode.Type == CssNodeType.Value)
                    {
                        currentNode.TextBuilder.Append(t.Text);
                        currentNode = currentNode.Parent;
                    }
                    else
                    {
                        currentNode = currentNode.Parent.Parent;
                    }
                    break;

                case CssTokenType.Whitespace:
                    currentNode.TextBuilder.Append(t.Text);
                    break;
                }
            }

            return(doc);
        }