/// <summary> /// Clones the ContextObject into a new Detached object /// </summary> /// <returns></returns> public virtual ContextObject CloneForEdit(object newValue) { var contextClone = new ContextObject(_key, this, newValue) //note: Parent must be the original context so we can traverse up to an unmodified context { _isNaturalContext = false, }; return(contextClone); }
/// <summary> /// Clones the ContextObject into a new Detached object /// </summary> /// <returns></returns> public virtual ContextObject Copy() { var contextClone = new ContextObject(_key, _parent, _value) //note: Parent must be the original context so we can traverse up to an unmodified context { _isNaturalContext = true, }; return(contextClone); }
/// <summary> /// Clones the ContextObject into a new Detached object /// </summary> /// <returns></returns> public virtual ContextObject CloneForEdit() { var contextClone = new ContextObject(Options, Key, this, _value) //note: Parent must be the original context so we can traverse up to an unmodified context { IsNaturalContext = false, }; return(contextClone); }
/// <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, string key, ContextObject parent, object value) : base(key, parent, value) { Index = index; Last = last; }
/// <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, object value) : base(options, key, parent, value) { Index = index; Last = last; }
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); }
/// <summary> /// Initializes a new instance of the <see cref="ContextObject" /> class. /// </summary> public ContextObject([NotNull] ParserOptions options, [NotNull] string key, [CanBeNull] ContextObject parent, object value) { Options = options ?? throw new ArgumentNullException(nameof(options)); Key = key; Parent = parent; _value = value; if (Parent != null) { CancellationToken = Parent.CancellationToken; } IsNaturalContext = Parent?.IsNaturalContext ?? true; }
internal ContextObject ExecuteObjectSelector(string key, Type type, ScopeData scopeData) { ContextObject innerContext = null; if (!scopeData.ParserOptions.HandleDictionaryAsObject && _value is IDictionary <string, object> dictList) { innerContext = scopeData.ParserOptions.CreateContextObject(key, dictList.Select(e => e), this); } else { if (_value != null) { innerContext = scopeData.ParserOptions.CreateContextObject(key, 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); } } return(innerContext ?? this); }
/// <inheritdoc /> public PartialContextObject(string key, ContextObject parent, object value) : base(key, parent, value) { }
/// <inheritdoc /> public PartialContextObject([NotNull] ParserOptions options, [NotNull] string key, [CanBeNull] ContextObject parent, object value) : base(options, key, parent, value) { }
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); }