예제 #1
0
        /// <summary>
        /// Parses the Template with the given options.
        /// </summary>
        /// <param name="parsingOptions">A set of options.</param>
        /// <returns></returns>
        public static ExtendedParseInformation ParseWithOptions(ParserOptions parsingOptions)
        {
            if (parsingOptions == null)
            {
                throw new ArgumentNullException(nameof(parsingOptions));
            }

            if (parsingOptions.StreamFactory == null)
            {
                throw new ArgumentNullException(nameof(parsingOptions), "The given Stream is null");
            }

            var tokens        = new Queue <TokenPair>(Tokenizer.Tokenize(parsingOptions.Template));
            var inferredModel = new InferredTemplateModel();

            var internalTemplate = Parse(tokens, parsingOptions, parsingOptions.WithModelInference ? inferredModel : null);
            Func <IDictionary <string, object>, CancellationToken, Stream> template = (model, token) =>
            {
                var targetStream = parsingOptions.StreamFactory();
                if (!targetStream.CanWrite)
                {
                    throw new InvalidOperationException("The stream is ReadOnly");
                }

                using (var streamWriter = new StreamWriter(targetStream, parsingOptions.Encoding, BufferSize, true))
                {
                    var context = new ContextObject
                    {
                        Value             = model,
                        Key               = "",
                        Options           = parsingOptions,
                        CancellationToken = token
                    };
                    internalTemplate(streamWriter, context);
                    streamWriter.Flush();
                }
                return(targetStream);
            };

            var result = new ExtendedParseInformation
            {
                InferredModel = inferredModel,
                ParsedTemplateWithCancellation = template
            };

            return(result);
        }
예제 #2
0
        private static Action <StreamWriter, ContextObject> HandleFormattingValue(
            TokenPair currentToken,
            ParserOptions options,
            InferredTemplateModel scope)
        {
            return((builder, context) =>
            {
                scope = scope?.GetInferredModelForPath(currentToken.Value, InferredTemplateModel.UsedAs.Scalar);

                if (context == null)
                {
                    return;
                }
                var c = context.GetContextForPath(currentToken.Value, true);

                context.FormattingValue = c.Format(currentToken.FormatAs, c.Value);
            });
        }
예제 #3
0
 private static Action <StreamWriter, ContextObject> PrintFormattedValues(
     TokenPair currentToken,
     ParserOptions options,
     InferredTemplateModel currentScope)
 {
     return((builder, context) =>
     {
         if (context == null)
         {
             return;
         }
         string value = null;
         if (context.FormattingValue != null)
         {
             value = context.FormattingValue.ToString();
             context.FormattingValue = null;
         }
         HandleContent(value)(builder, context);
     });
 }
예제 #4
0
        private static Action <StreamWriter, ContextObject> HandleSingleValue(TokenPair token, ParserOptions options,
                                                                              InferredTemplateModel scope)
        {
            scope = scope?.GetInferredModelForPath(token.Value, InferredTemplateModel.UsedAs.Scalar);

            return((builder, context) =>
            {
                //try to locate the value in the context, if it exists, append it.
                var c = context?.GetContextForPath(token.Value);
                if (c?.Value != null)
                {
                    if (token.Type == TokenType.EscapedSingleValue && !options.DisableContentEscaping)
                    {
                        HandleContent(RtfEncodeString(c.ToString(), options))(builder, c);
                    }
                    else
                    {
                        HandleContent(c.ToString())(builder, c);
                    }
                }
            });
        }
예제 #5
0
        private InferredTemplateModel GetContextForPath(Queue <String> elements)
        {
            var retval = this;

            if (elements.Any())
            {
                var element = elements.Dequeue();
                if (element.StartsWith(".."))
                {
                    if (Parent != null)
                    {
                        retval = Parent.GetContextForPath(elements);
                    }
                    else
                    {
                        //Calling "../" too much may be "ok" in that if we're at root,
                        //we may just stop recursion and traverse down the path.
                        retval = GetContextForPath(elements);
                    }
                }
                //TODO: handle array accessors and maybe "special" keys.
                else
                {
                    //ALWAYS return the context, even if the value is null.

                    InferredTemplateModel innerContext = null;
                    if (!Children.TryGetValue(element, out innerContext))
                    {
                        innerContext        = new InferredTemplateModel();
                        innerContext.Key    = element;
                        innerContext.Parent = this;
                        Children[element]   = innerContext;
                    }
                    retval = innerContext.GetContextForPath(elements);
                }
            }
            return(retval);
        }
예제 #6
0
        private static Action <StreamWriter, ContextObject> Parse(Queue <TokenPair> tokens, ParserOptions options,
                                                                  InferredTemplateModel currentScope = null)
        {
            var buildArray = new List <Action <StreamWriter, ContextObject> >();

            while (tokens.Any())
            {
                var currentToken = tokens.Dequeue();
                switch (currentToken.Type)
                {
                case TokenType.Comment:
                    break;

                case TokenType.Content:
                    buildArray.Add(HandleContent(currentToken.Value));
                    break;

                case TokenType.CollectionOpen:
                    buildArray.Add(HandleCollectionOpen(currentToken, tokens, options, currentScope));
                    break;

                case TokenType.ElementOpen:
                    buildArray.Add(HandleElementOpen(currentToken, tokens, options, currentScope));
                    break;

                case TokenType.InvertedElementOpen:
                    buildArray.Add(HandleInvertedElementOpen(currentToken, tokens, options, currentScope));
                    break;

                case TokenType.CollectionClose:
                case TokenType.ElementClose:
                    // This should immediately return if we're in the element scope,
                    // and if we're not, this should have been detected by the tokenizer!
                    return((builder, context) =>
                    {
                        foreach (var a in buildArray.TakeWhile(e => StopOrAbortBuilding(context)))
                        {
                            a(builder, context);
                        }
                    });

                case TokenType.Format:
                    buildArray.Add(HandleFormattingValue(currentToken, options, currentScope));
                    break;

                case TokenType.PrintFormatted:
                    buildArray.Add(PrintFormattedValues(currentToken, options, currentScope));
                    break;

                case TokenType.PrintSelf:
                    buildArray.Add(HandleSingleValue(currentToken, options, currentScope));
                    break;

                case TokenType.EscapedSingleValue:
                case TokenType.UnescapedSingleValue:
                    buildArray.Add(HandleSingleValue(currentToken, options, currentScope));
                    break;
                }
            }

            return((builder, context) =>
            {
                foreach (var a in buildArray.TakeWhile(e => StopOrAbortBuilding(context)))
                {
                    a(builder, context);
                }
            });
        }
예제 #7
0
        private static Action <StreamWriter, ContextObject> HandleCollectionOpen(TokenPair token, Queue <TokenPair> remainder,
                                                                                 ParserOptions options, InferredTemplateModel scope)
        {
            scope = scope?.GetInferredModelForPath(token.Value, InferredTemplateModel.UsedAs.Collection);

            var innerTemplate = Parse(remainder, options, scope);

            return((builder, context) =>
            {
                //if we're in the same scope, just negating, then we want to use the same object
                var c = context.GetContextForPath(token.Value);

                //"falsey" values by Javascript standards...
                if (!c.Exists())
                {
                    return;
                }

                if (c.Value is IEnumerable enumerable && !(enumerable is string) && !(enumerable is IDictionary <string, object>))
                {
                    var index = 0;
                    var enumerator = enumerable.GetEnumerator();
                    if (enumerator.MoveNext())
                    {
                        var current = enumerator.Current;
                        object next;
                        do
                        {
                            if (enumerator.MoveNext())
                            {
                                next = enumerator.Current;
                            }
                            else
                            {
                                next = null;
                            }
                            var innerContext = new ContextCollection(index, next == null)
                            {
                                Value = current,
                                Key = string.Format("[{0}]", index),
                                Options = options,
                                Parent = c
                            };
                            innerTemplate(builder, innerContext);
                            index++;
                            current = next;
                        } while (current != null);
                    }
                }
예제 #8
0
        private static Action <StreamWriter, ContextObject> HandleInvertedElementOpen(TokenPair token,
                                                                                      Queue <TokenPair> remainder,
                                                                                      ParserOptions options, InferredTemplateModel scope)
        {
            scope = scope?.GetInferredModelForPath(token.Value, InferredTemplateModel.UsedAs.ConditionalValue);

            var innerTemplate = Parse(remainder, options, scope);

            return((builder, context) =>
            {
                var c = context.GetContextForPath(token.Value);
                //"falsey" values by Javascript standards...
                if (!c.Exists())
                {
                    innerTemplate(builder, c);
                }
            });
        }