Exemplo n.º 1
0
        /// <summary>
        /// Creates a new <tt>Template</tt> object from liquid source code
        /// </summary>
        /// <param name="source">The Liquid Template string</param>
        /// <param name="syntaxCompatibilityLevel">The Liquid syntax flag used for backward compatibility</param>
        /// <returns></returns>
        public static Template Parse(string source, SyntaxCompatibility syntaxCompatibilityLevel)
        {
            Template template = new Template();

            template.ParseInternal(source, syntaxCompatibilityLevel);
            return(template);
        }
Exemplo n.º 2
0
 public static void AssertTemplateResult(string expected, string template, SyntaxCompatibility syntax = SyntaxCompatibility.DotLiquid20)
 {
     AssertTemplateResult(expected: expected, template: template, localVariables: null, syntax: syntax);
 }
Exemplo n.º 3
0
        public static void AssertTemplateResult(string expected, string template, Hash localVariables, IEnumerable <Type> localFilters, SyntaxCompatibility syntax = SyntaxCompatibility.DotLiquid20)
        {
            var parameters = new RenderParameters(System.Globalization.CultureInfo.CurrentCulture)
            {
                LocalVariables           = localVariables,
                SyntaxCompatibilityLevel = syntax,
                Filters = localFilters
            };

            Assert.AreEqual(expected, Template.Parse(template).Render(parameters));
        }
Exemplo n.º 4
0
 public static void AssertTemplateResult(string expected, string template, object anonymousObject, INamingConvention namingConvention, SyntaxCompatibility syntax = SyntaxCompatibility.DotLiquid20)
 {
     LockTemplateStaticVars(namingConvention, () =>
     {
         var localVariables = anonymousObject == null ? null : Hash.FromAnonymousObject(anonymousObject);
         var parameters     = new RenderParameters(System.Globalization.CultureInfo.CurrentCulture)
         {
             LocalVariables           = localVariables,
             SyntaxCompatibilityLevel = syntax
         };
         Assert.AreEqual(expected, Template.Parse(template).Render(parameters));
     });
 }
Exemplo n.º 5
0
 /// <summary>
 /// Parse source code.
 /// Returns self for easy chaining
 /// </summary>
 /// <param name="source">The source code.</param>
 /// <param name="syntaxCompatibilityLevel">The Liquid syntax flag used for backward compatibility</param>
 /// <returns>The template.</returns>
 internal Template ParseInternal(string source, SyntaxCompatibility syntaxCompatibilityLevel)
 {
     this.Root = new Document();
     this.Root.Initialize(tagName: null, markup: null, tokens: Tokenizer.Tokenize(source, syntaxCompatibilityLevel));
     return(this);
 }
Exemplo n.º 6
0
        /// <summary>
        /// Splits a string into an array of `tokens` that represent either a tag, object/variable, or literal string
        /// </summary>
        /// <param name="source">The Liquid Template string</param>
        /// <param name="syntaxCompatibilityLevel">The Liquid syntax flag used for backward compatibility</param>
        /// <exception cref="SyntaxException"></exception>
        internal static List <string> Tokenize(string source, SyntaxCompatibility syntaxCompatibilityLevel)
        {
            if (string.IsNullOrEmpty(source))
            {
                return(new List <string>());
            }

            // Trim leading whitespace - backward compatible list of chars
            var whitespaceChars = syntaxCompatibilityLevel < SyntaxCompatibility.DotLiquid22 ? WhitespaceCharsV20 : WhitespaceCharsV22;

            // Trim trailing whitespace - new lines or spaces/tabs but not both
            if (syntaxCompatibilityLevel < SyntaxCompatibility.DotLiquid22)
            {
                source = DotLiquid.Tags.Literal.FromShortHand(source);
                source = DotLiquid.Tags.Comment.FromShortHand(source);
                source = Regex.Replace(source, string.Format(@"-({0}|{1})(\n|\r\n|[ \t]+)?", Liquid.VariableEnd, Liquid.TagEnd), "$1", RegexOptions.None, Template.RegexTimeOut);
            }

            var tokens = new List <string>();

            using (var markupEnumerator = new CharEnumerator(source))
            {
                var match = LiquidAnyStartingTagRegex.Match(source, markupEnumerator.Position);
                while (match.Success)
                {
                    // Check if there was a literal before the tag
                    if (match.Index > markupEnumerator.Position)
                    {
                        var tokenBeforeMatch = ReadChars(markupEnumerator, match.Index - markupEnumerator.Position);
                        if (match.Groups[2].Success)
                        {
                            tokenBeforeMatch = tokenBeforeMatch.TrimEnd(whitespaceChars);
                        }
                        if (tokenBeforeMatch != string.Empty)
                        {
                            tokens.Add(tokenBeforeMatch);
                        }
                    }

                    var isTag = match.Groups[1].Value == "{%";
                    // Ignore hyphen in tag name, add the tag/variable itself
                    var nextToken = new StringBuilder(markupEnumerator.Remaining);
                    nextToken.Append(match.Groups[1].Value);
                    ReadChars(markupEnumerator, match.Length);

                    // Add the parameters and tag closure
                    if (isTag)
                    {
                        if (!ReadToEndOfTag(nextToken, markupEnumerator, SearchQuoteOrTagEnd, syntaxCompatibilityLevel))
                        {
                            throw new SyntaxException(Liquid.ResourceManager.GetString("BlockTagNotTerminatedException"), nextToken.ToString(), Liquid.TagEnd);
                        }
                    }
                    else
                    {
                        if (!ReadToEndOfTag(nextToken, markupEnumerator, SearchQuoteOrVariableEnd, syntaxCompatibilityLevel))
                        {
                            throw new SyntaxException(Liquid.ResourceManager.GetString("BlockVariableNotTerminatedException"), nextToken.ToString(), Liquid.VariableEnd);
                        }
                    }

                    var token = nextToken.ToString();
                    tokens.Add(token);

                    if (isTag)
                    {
                        var tagMatch = TagNameRegex.Match(token);
                        if (tagMatch.Success)
                        {
                            var tagName = tagMatch.Groups[1].Value;
                            if (Template.IsRawTag(tagName))
                            {
                                var endTagRegex = EndTagRegexes.GetOrAdd(tagName, (key) => R.B(@"{0}-?\s*end{1}\s*-?{2}", Liquid.TagStart, key, Liquid.TagEnd));
                                var endTagMatch = endTagRegex.Match(source, markupEnumerator.Position);
                                if (!endTagMatch.Success)
                                {
                                    throw new SyntaxException(Liquid.ResourceManager.GetString("BlockTagNotClosedException"), tagName);
                                }
                                if (endTagMatch.Index > markupEnumerator.Position) //add tag of everything between start and end tags
                                {
                                    tokens.Add(ReadChars(markupEnumerator, endTagMatch.Index - markupEnumerator.Position));
                                }
                            }
                        }
                    }
                    match = LiquidAnyStartingTagRegex.Match(source, markupEnumerator.Position);
                }

                if (markupEnumerator.Remaining > 0)
                {
                    tokens.Add(ReadChars(markupEnumerator, markupEnumerator.Remaining));
                }
            }

            return(tokens);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Reads a tag or object variable until the end sequence, <tt>%}</tt> or <tt>}}</tt> respectively and advances the enumerator position
        /// </summary>
        /// <param name="sb">The StringBuilder to write to</param>
        /// <param name="markupEnumerator">The string enumerator</param>
        /// <param name="searchChars">The character set to search for</param>
        /// <returns>True if reaches end sequence, otherwise false</returns>
        private static bool ReadToEndOfTag(StringBuilder sb, CharEnumerator markupEnumerator, HashSet <char> searchChars, SyntaxCompatibility syntaxCompatibilityLevel)
        {
            while (markupEnumerator.AppendNext(sb))
            {
                char nextChar = markupEnumerator.Current;
                if (searchChars.Contains(nextChar))
                {
                    switch (nextChar)
                    {
                    case '\'':
                    case '"':
                        ReadToChar(sb, markupEnumerator, nextChar);
                        break;

                    case '}':
                    case '%':
                        if (markupEnumerator.Remaining > 0 && markupEnumerator.Next == '}')
                        {
                            var previousCharIsWhitespaceControl = syntaxCompatibilityLevel >= SyntaxCompatibility.DotLiquid22 && markupEnumerator.Previous == '-';
                            markupEnumerator.AppendNext(sb);
                            if (previousCharIsWhitespaceControl)
                            {
                                // Remove hyphen from token
                                sb.Remove(sb.Length - 3, 1);

                                // Trim trailing whitespace by skipping ahead beyond the tag end
                                while (markupEnumerator.Remaining > 0)
                                {
                                    if (((uint)markupEnumerator.Next - '\t') <= 5 || markupEnumerator.Next == ' ')
                                    {
                                        markupEnumerator.MoveNext();
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                            }
                            return(true);
                        }
                        break;
                    }
                }
            }
            ;

            // Somehow we reached the end without finding the end character(s)
            return(false);
        }