Exemplo n.º 1
0
        internal ContextObject LoopContextTraversable(Traversable elements,
                                                      ScopeData scopeData,
                                                      IMorestachioExpression morestachioExpression)
        {
            ContextObject context = this;

            while (elements != null && elements.HasValue)
            {
                context  = context.GetContextForPathInternal(elements, scopeData, morestachioExpression);
                elements = elements.Next();
            }

            return(context);
        }
Exemplo n.º 2
0
        private async ContextObjectPromise GetContextForPathInternal(
            Traversable elements,
            ScopeData scopeData,
            IMorestachioExpression morestachioExpression)
        {
            var retval = this;

            if (elements == null)
            {
                return(retval);
            }

            var preHandeld = HandlePathContext(elements, elements.Current, morestachioExpression, scopeData);

            if (preHandeld != null)
            {
                return(preHandeld);
            }

            var type = Value?.GetType();

            if (elements.Current.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.GetContextForPathInternal(elements.Next(), scopeData,
                                                                        morestachioExpression);
                }
            }
            else if (elements.Current.Value == PathType.ParentSelector)             //go one level up
            {
                if (Parent != null)
                {
                    var           parent        = FindNextNaturalContextObject();
                    ContextObject parentsRetVal = null;
                    if (parent != null && parent.Parent != null)
                    {
                        parentsRetVal = await parent.Parent
                                        .GetContextForPathInternal(elements.Next(), scopeData, morestachioExpression);
                    }

                    if (parentsRetVal != null)
                    {
                        retval = parentsRetVal;
                    }
                    else
                    {
                        retval = await GetContextForPathInternal(elements.Next(), scopeData, morestachioExpression);
                    }
                }
                else
                {
                    retval = await GetContextForPathInternal(elements.Next(), scopeData, morestachioExpression);
                }
            }
            else if (elements.Current.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(elements.Current.Key, CancellationToken,
                                                               dictList.Select(e => e), this);
                    break;

                default:
                {
                    if (Value != null)
                    {
                        innerContext = Options.CreateContextObject(elements.Current.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.GetContextForPathInternal(elements.Next(), scopeData,
                                                                      morestachioExpression);
            }
            else if (elements.Current.Value == PathType.Boolean)
            {
                if (elements.Current.Key == "true" || elements.Current.Key == "false")
                {
                    var booleanContext =
                        Options.CreateContextObject(".", CancellationToken, elements.Current.Key == "true", this);
                    booleanContext.IsNaturalContext = IsNaturalContext;
                    return(await booleanContext.GetContextForPathInternal(elements.Next(), scopeData,
                                                                          morestachioExpression));
                }
            }
            else if (elements.Current.Value == PathType.Null)
            {
                return(Options.CreateContextObject("x:null", CancellationToken, null, null));
            }
            else if (elements.Current.Value == PathType.DataPath)
            {
                //await EnsureValue();
                if (Value is null)
                {
                    return(Options.CreateContextObject("x:null", CancellationToken, null));
                }
                //TODO: handle array accessors and maybe "special" keys.
                //ALWAYS return the context, even if the value is null.

                var innerContext = Options.CreateContextObject(elements.Current.Key, CancellationToken, null, this);
                if (Options.ValueResolver?.CanResolve(type, Value, elements.Current.Key, innerContext) == true)
                {
                    innerContext._value = Options.ValueResolver.Resolve(type, Value, elements.Current.Key, innerContext);
                }
                else if (!Options.HandleDictionaryAsObject && Value is IDictionary <string, object> ctx)
                {
                    if (!ctx.TryGetValue(elements.Current.Key, out var o))
                    {
                        Options.OnUnresolvedPath(new InvalidPathEventArgs(this, morestachioExpression,
                                                                          elements.Current.Key, Value?.GetType()));
                    }

                    innerContext._value = o;
                }
                else if (Value is IMorestachioPropertyResolver cResolver)
                {
                    if (!cResolver.TryGetValue(elements.Current.Key, out var o))
                    {
                        Options.OnUnresolvedPath(new InvalidPathEventArgs(this, morestachioExpression,
                                                                          elements.Current.Key, Value?.GetType()));
                    }

                    innerContext._value = o;
                }
                else if (Value != null)
                {
                    if (Value is ICustomTypeDescriptor descriptor)
                    {
                        var propertyDescriptor = descriptor.GetProperties().Find(elements.Current.Key, false);
                        if (propertyDescriptor != null)
                        {
                            innerContext._value = propertyDescriptor.GetValue(Value);
                        }
                        else
                        {
                            Options.OnUnresolvedPath(new InvalidPathEventArgs(this, morestachioExpression,
                                                                              elements.Current.Key, Value?.GetType()));
                        }
                    }
                    else
                    {
                        var propertyInfo = type.GetTypeInfo().GetProperty(elements.Current.Key);
                        if (propertyInfo != null)
                        {
                            innerContext._value = propertyInfo.GetValue(Value);
                        }
                        else
                        {
                            Options.OnUnresolvedPath(new InvalidPathEventArgs(this, morestachioExpression,
                                                                              elements.Current.Key, Value?.GetType()));
                        }
                    }
                }

                retval = await innerContext.GetContextForPathInternal(elements.Next(), scopeData,
                                                                      morestachioExpression);
            }

            return(retval);
        }