Пример #1
0
        /// <summary>
        ///     Clones the ContextObject into a new Detached object
        /// </summary>
        /// <returns></returns>
        public virtual ContextObject Clone()
        {
            var contextClone = new ContextObject(Options, Key, this)             //note: Parent must be the original context so we can traverse up to an unmodified context
            {
                Value            = Value,
                IsNaturalContext = false
            };

            return(contextClone);
        }
Пример #2
0
 /// <summary>
 ///     ctor
 /// </summary>
 /// <param name="index">the current index of the item inside the collection</param>
 /// <param name="last">true if its the last item</param>
 /// <param name="options"></param>
 /// <param name="key"></param>
 public ContextCollection(long index,
                          bool last,
                          [NotNull] ParserOptions options,
                          string key,
                          [CanBeNull] ContextObject parent)
     : base(options, key, parent)
 {
     Index = index;
     Last  = last;
 }
Пример #3
0
        /// <summary>
        ///     Clones the ContextObject into a new Detached object
        /// </summary>
        /// <returns></returns>
        public virtual ContextObject Copy()
        {
            var contextClone = new ContextObject(Options, Key, Parent)             //note: Parent must be the original context so we can traverse up to an unmodified context
            {
                Value            = Value,
                IsNaturalContext = true,
                AbortGeneration  = AbortGeneration
            };

            return(contextClone);
        }
Пример #4
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ContextObject"/> class.
 /// </summary>
 /// <param name="options">The options.</param>
 /// <param name="key">The key as seen in the Template</param>
 public ContextObject([NotNull] ParserOptions options, [NotNull] string key, [CanBeNull] ContextObject parent)
 {
     Options = options;
     Key     = key;
     Parent  = parent;
     if (Parent != null)
     {
         CancellationToken = Parent.CancellationToken;
         AbortGeneration   = Parent.AbortGeneration;
     }
     IsNaturalContext = Parent?.IsNaturalContext ?? true;
 }
Пример #5
0
        /// <summary>
        ///     Clones the ContextObject into a new Detached object
        /// </summary>
        /// <returns></returns>
        public virtual ContextObject Clone()
        {
            var contextClone = new ContextObject(Options, Key)
            {
                CancellationToken = CancellationToken,
                Parent            = Parent,
                AbortGeneration   = AbortGeneration,
                Value             = Value
            };

            return(contextClone);
        }
Пример #6
0
        /// <summary>
        ///     Will walk the path by using the path seperator "." and evaluate the object at the end
        /// </summary>
        /// <param name="path"></param>
        /// <param name="scopeData"></param>
        /// <returns></returns>
        internal async Task <ContextObject> GetContextForPath(string path, ScopeData scopeData)
        {
            var elements = new Queue <string>();

            foreach (var m in PathFinder.Matches(path).OfType <Match>())
            {
                elements.Enqueue(m.Value);
            }

            if (elements.Any())
            {
                //look at the first element if its an alias switch to that alias
                var peekPathPart = elements.Peek();
                if (scopeData.Alias.TryGetValue(peekPathPart, out var alias))
                {
                    elements.Dequeue();
                    return(await alias.GetContextForPath(elements, scopeData));
                }

                //check if this part of the path can be seen as an number
                if (Number.TryParse(peekPathPart, out var isNumber))
                {
                    elements.Dequeue();
                    ContextObject contextObject;
                    if (elements.Count > 0)
                    {
                        var peekNextPathPart = elements.Peek();
                        if (Number.TryParse(peekPathPart
                                            + CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator
                                            + peekNextPathPart, out var floatingNumber))
                        {
                            elements.Dequeue();
                            contextObject                  = new ContextObject(Options, ".", this);
                            contextObject.Value            = floatingNumber;
                            contextObject.IsNaturalContext = IsNaturalContext;
                            return(await contextObject.GetContextForPath(elements, scopeData));
                        }
                    }

                    contextObject                  = new ContextObject(Options, ".", this);
                    contextObject.Value            = isNumber;
                    contextObject.IsNaturalContext = IsNaturalContext;
                    return(await contextObject.GetContextForPath(elements, scopeData));
                }
            }

            return(await GetContextForPath(elements, scopeData));
        }
Пример #7
0
        /// <inheritdoc />
        protected override ContextObject HandlePathContext(Queue <KeyValuePair <string, PathType> > elements,
                                                           KeyValuePair <string, PathType> path)
        {
            if (path.Value != PathType.DataPath)
            {
                return(null);
            }

            var innerContext = new ContextObject(Options, path.Key, this);

            object value = null;

            if (path.Key.Equals("$first"))
            {
                value = Index == 0;
            }
            else if (path.Key.Equals("$index"))
            {
                value = Index;
            }
            else if (path.Key.Equals("$middel"))
            {
                value = Index != 0 && !Last;
            }
            else if (path.Key.Equals("$last"))
            {
                value = Last;
            }
            else if (path.Key.Equals("$odd"))
            {
                value = Index % 2 != 0;
            }
            else if (path.Key.Equals("$even"))
            {
                value = Index % 2 == 0;
            }

            innerContext.Value = value;
            return(value == null ? null : innerContext);
        }
Пример #8
0
        /// <inheritdoc />
        protected override ContextObject HandlePathContext(Queue <string> elements, string path)
        {
            var innerContext = new ContextObject(Options, path);

            innerContext.Parent = this;

            object value = null;

            if (path.Equals("$first"))
            {
                value = Index == 0;
            }
            else if (path.Equals("$index"))
            {
                value = Index;
            }
            else if (path.Equals("$middel"))
            {
                value = Index != 0 && !Last;
            }
            else if (path.Equals("$last"))
            {
                value = Last;
            }
            else if (path.Equals("$odd"))
            {
                value = Index % 2 != 0;
            }
            else if (path.Equals("$even"))
            {
                value = Index % 2 == 0;
            }

            innerContext.Value = value;
            return(value == null ? null : innerContext);
        }
Пример #9
0
        private async Task <ContextObject> GetContextForPath(Queue <string> elements, ScopeData scopeData)
        {
            var retval = this;

            if (elements.Any())
            {
                var path       = elements.Dequeue();
                var preHandeld = HandlePathContext(elements, path);
                if (preHandeld != null)
                {
                    return(preHandeld);
                }

                if (path.StartsWith("~"))                 //go the root object
                {
                    var parent     = Parent;
                    var lastParent = parent;
                    while (parent != null)
                    {
                        parent = parent.Parent;
                        if (parent != null)
                        {
                            lastParent = parent;
                        }
                    }

                    if (lastParent != null)
                    {
                        retval = await lastParent.GetContextForPath(elements, scopeData);
                    }
                }
                else if (path.Equals("$recursion"))                 //go the root object
                {
                    retval = new ContextObject(Options, path, this)
                    {
                        Value = scopeData.PartialDepth.Count
                    };
                }
                else if (path.StartsWith(".."))                 //go one level up
                {
                    if (Parent != null)
                    {
                        var parentsRetVal = (await(FindNextNaturalContextObject()?.Parent?.GetContextForPath(elements, scopeData) ?? Task.FromResult((ContextObject)null)));
                        if (parentsRetVal != null)
                        {
                            retval = parentsRetVal;
                        }
                        else
                        {
                            retval = await GetContextForPath(elements, scopeData);
                        }
                    }
                    else
                    {
                        retval = await GetContextForPath(elements, scopeData);
                    }
                }
                else
                {
                    await EnsureValue();

                    var type = Value?.GetType();
                    if (path.StartsWith("?"))                     //enumerate ether an IDictionary, an cs object or an IEnumerable to a KeyValuePair array
                    {
                        //ALWAYS return the context, even if the value is null.
                        var innerContext = new ContextObject(Options, path, this);
                        switch (Value)
                        {
                        case IDictionary <string, object> dictList:
                            innerContext.Value = dictList.Select(e => e);
                            break;

                        //This is a draft that i have discarded as its more likely to enumerate a single IEnumerable with #each alone
                        //case IEnumerable ctx:
                        //	innerContext.Value = ctx.OfType<object>().Select((item, index) => new KeyValuePair<string, object>(index.ToString(), item));
                        //	break;
                        default:
                        {
                            if (Value != null)
                            {
                                innerContext.Value = type
                                                     .GetTypeInfo()
                                                     .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                                                     .Where(e => !e.IsSpecialName && !e.GetIndexParameters().Any())
                                                     .Select(e => new KeyValuePair <string, object>(e.Name, e.GetValue(Value)));
                            }

                            break;
                        }
                        }

                        retval = await innerContext.GetContextForPath(elements, scopeData);
                    }
                    //TODO: handle array accessors and maybe "special" keys.
                    else
                    {
                        //ALWAYS return the context, even if the value is null.
                        var innerContext = new ContextObject(Options, path, this);
                        if (Options.ValueResolver?.CanResolve(type, Value, path, innerContext) == true)
                        {
                            innerContext.Value = Options.ValueResolver.Resolve(type, Value, path, innerContext);
                        }
                        else if (Value is IDictionary <string, object> ctx)
                        {
                            if (!ctx.TryGetValue(path, out var o))
                            {
                                Options.OnUnresolvedPath(path, type);
                            }
                            innerContext.Value = o;
                        }
                        else if (Value != null)
                        {
                            var propertyInfo = type.GetTypeInfo().GetProperty(path);
                            if (propertyInfo != null)
                            {
                                innerContext.Value = propertyInfo.GetValue(Value);
                            }
                            else
                            {
                                Options.OnUnresolvedPath(path, type);
                            }
                        }

                        retval = await innerContext.GetContextForPath(elements, scopeData);
                    }
                }
            }

            return(retval);
        }
Пример #10
0
        private async Task <ContextObject> GetContextForPath(
            Queue <KeyValuePair <string, PathType> > elements,
            ScopeData scopeData)
        {
            var retval = this;

            if (elements.Any())
            {
                var path       = elements.Dequeue();
                var preHandeld = HandlePathContext(elements, path);
                if (preHandeld != null)
                {
                    return(preHandeld);
                }
                var type = Value?.GetType();

                if (path.Value == PathType.RootSelector)                 //go the root object
                {
                    var parent     = Parent ?? this;
                    var lastParent = parent;
                    while (parent != null)
                    {
                        parent = parent.Parent;
                        if (parent != null)
                        {
                            lastParent = parent;
                        }
                    }

                    if (lastParent != null)
                    {
                        retval = await lastParent.GetContextForPath(elements, scopeData);
                    }
                }
                else if (path.Value == PathType.ParentSelector)                 //go one level up
                {
                    if (Parent != null)
                    {
                        var parentsRetVal = (await(FindNextNaturalContextObject()?.Parent?.GetContextForPath(elements, scopeData) ?? Task.FromResult((ContextObject)null)));
                        if (parentsRetVal != null)
                        {
                            retval = parentsRetVal;
                        }
                        else
                        {
                            retval = await GetContextForPath(elements, scopeData);
                        }
                    }
                    else
                    {
                        retval = await GetContextForPath(elements, scopeData);
                    }
                }
                else if (path.Value == PathType.ObjectSelector)                 //enumerate ether an IDictionary, an cs object or an IEnumerable to a KeyValuePair array
                {
                    await EnsureValue();

                    if (Value is null)
                    {
                        return(Options.CreateContextObject("x:null", CancellationToken, null));
                    }
                    //ALWAYS return the context, even if the value is null.
                    ContextObject innerContext = null;
                    switch (Value)
                    {
                    case IDictionary <string, object> dictList:
                        innerContext = Options.CreateContextObject(path.Key, CancellationToken,
                                                                   dictList.Select(e => e), this);
                        break;

                    default:
                    {
                        if (Value != null)
                        {
                            innerContext = Options.CreateContextObject(path.Key, CancellationToken,
                                                                       type
                                                                       .GetTypeInfo()
                                                                       .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                                                                       .Where(e => !e.IsSpecialName && !e.GetIndexParameters().Any())
                                                                       .Select(e => new KeyValuePair <string, object>(e.Name, e.GetValue(Value))),
                                                                       this);
                        }

                        break;
                    }
                    }

                    retval = await innerContext.GetContextForPath(elements, scopeData);
                }
                else if (path.Value == PathType.Number)
                {
                    //check if this part of the path can be seen as an number
                    if (Number.TryParse(path.Key, Options.CultureInfo, out var isNumber))
                    {
                        var contextObject = Options.CreateContextObject(".", CancellationToken, isNumber, this);
                        contextObject.IsNaturalContext = IsNaturalContext;
                        return(await contextObject.GetContextForPath(elements, scopeData));
                    }
                }
                else if (path.Value == PathType.Boolean)
                {
                    if (path.Key == "true" || path.Key == "false")
                    {
                        var booleanContext = Options.CreateContextObject(".", CancellationToken, path.Key == "true", this);
                        booleanContext.IsNaturalContext = IsNaturalContext;
                        return(await booleanContext.GetContextForPath(elements, scopeData));
                    }
                }
                else if (path.Value == PathType.DataPath)
                {
                    if (path.Key.Equals("$recursion"))                     //go the root object
                    {
                        retval = Options.CreateContextObject(path.Key, CancellationToken, scopeData.PartialDepth.Count, this);
                    }
                    else
                    {
                        await EnsureValue();

                        if (Value is null)
                        {
                            return(Options.CreateContextObject("x:null", CancellationToken, null));
                        }
                        //TODO: handle array accessors and maybe "special" keys.
                        else
                        {
                            //ALWAYS return the context, even if the value is null.

                            var innerContext = Options.CreateContextObject(path.Key, CancellationToken, null, this);
                            if (Options.ValueResolver?.CanResolve(type, Value, path.Key, innerContext) == true)
                            {
                                innerContext.Value = Options.ValueResolver.Resolve(type, Value, path.Key, innerContext);
                            }
                            else if (Value is IDictionary <string, object> ctx)
                            {
                                if (!ctx.TryGetValue(path.Key, out var o))
                                {
                                    Options.OnUnresolvedPath(path.Key, type);
                                }
                                innerContext.Value = o;
                            }
                            else if (Value != null)
                            {
                                var propertyInfo = type.GetTypeInfo().GetProperty(path.Key);
                                if (propertyInfo != null)
                                {
                                    innerContext.Value = propertyInfo.GetValue(Value);
                                }
                                else
                                {
                                    Options.OnUnresolvedPath(path.Key, type);
                                }
                            }

                            retval = await innerContext.GetContextForPath(elements, scopeData);
                        }
                    }
                }
            }

            return(retval);
        }