public TypedObjectAccessor(Type targetType, MemberRenamerDelegate renamer)
 {
     _type    = targetType ?? throw new ArgumentNullException(nameof(targetType));
     _renamer = renamer ?? StandardMemberRenamer.Default;
     _members = new Dictionary <string, MemberInfo>();
     PrepareMembers();
 }
Example #2
0
        public async Task OrderStatusNotify(string email, Order orderId, OrderStatus newOrderStatus)
        {
            var statusIdle = false;

            if (newOrderStatus != orderId.Status)
            {
                statusIdle = true;
            }
            if (statusIdle)
            {
                MemberRenamerDelegate memberRenamer = member => member.Name;
                var templateContentSubject          = await File.ReadAllTextAsync(templateSubjectFrom);

                var    templateSubject     = Template.Parse(templateContentSubject);
                var    subject             = templateSubject.Render(new { OrderId = orderId }, memberRenamer);
                string from                = "Rui Dias";
                var    templateContentBody = await File.ReadAllTextAsync(templateBodyFrom);

                var templateBody = Template.Parse(templateContentBody);
                var message      = templateBody.Render(
                    new { OrderId = orderId, From = from, NewOrderStatus = newOrderStatus != orderId.Status }
                    );
                await _emailSender.SendEmailAsync(email, subject, message);
            }
        }
Example #3
0
        public static object Evaluate(string expression, object model, MemberRenamerDelegate memberRenamer = null, MemberFilterDelegate memberFilter = null)
        {
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }
            var lexerOption = new LexerOptions()
            {
                Mode = ScriptMode.ScriptOnly
            };
            var template = Parse(expression, lexerOptions: lexerOption);

            return(template.Evaluate(model, memberRenamer, memberFilter));
        }
Example #4
0
        /// <summary>
        /// Renders this template using the specified object model.
        /// </summary>
        /// <param name="model">The object model.</param>
        /// <param name="memberRenamer">The member renamer used to import this .NET object and transitive objects. See member renamer documentation for more details.</param>
        /// <returns>A rendering result as a string </returns>
        public string Render(object model = null, MemberRenamerDelegate memberRenamer = null)
        {
            var scriptObject = new ScriptObject();

            if (model != null)
            {
                scriptObject.Import(model, renamer: memberRenamer);
            }

            var context = _lexerOptions.Mode == ScriptMode.Liquid ? new LiquidTemplateContext() : new TemplateContext();

            context.MemberRenamer = memberRenamer;
            context.PushGlobal(scriptObject);
            return(Render(context));
        }
        public void ReturnsPdfPageFromScriban()
        {
            var template = Template.Parse(TemplateContent());


            var catalogModel = new CatalogIndexViewModel();

            var items = new List <CatalogItemViewModel>();

            items.Add(new CatalogItemViewModel()
            {
                Name = "Name_1", Price = 1.2m, PriceSymbol = "€"
            });
            items.Add(new CatalogItemViewModel()
            {
                Name = "Name_2", Price = 2.2m, PriceSymbol = "€"
            });
            catalogModel.CatalogItems = items;

            var listCatalogItems = new List <CatalogItemViewModel>();

            foreach (var item in catalogModel.CatalogItems)
            {
                listCatalogItems.Add(
                    new CatalogItemViewModel()
                {
                    Name        = item.Name,
                    Price       = item.Price,
                    ShowPrice   = item.ShowPrice,
                    PriceSymbol = item.PriceSymbol,
                    PictureUri  = System.IO.Path.GetFullPath($"~{item.PictureUri}").Replace("~", "wwwroot")
                                  //PictureUri = "C:\\Formacao\\ASP.Net\\desenvolvimento\\eShopOnWeb\\src\\Web\\wwwroot\\images\\products\\1.png"
                }
                    );
            }

            MemberRenamerDelegate memberRenamer = member => member.Name;
            var pp   = new { Data = listCatalogItems, Date = DateTime.Now.ToString(), Year = DateTime.Now.Year  };
            var html = template.Render(pp, memberRenamer);

            // Assert
            Assert.Contains("Name_1", html);
        }
Example #6
0
        public static string ScribanParse(string template, dynamic model, MemberRenamerDelegate f = null)
        {
            try
            {
                return(ScribanRawParse(template, model, f));
            }
            catch (Exception e)
            {
                var errors = ScribanErrors(template, model, f);
                var msg    = $"{e.Message} {template} parse error with model\n";
                Console.Error.WriteLine(msg);
                if (e.InnerException != null)
                {
                    Console.Error.WriteLine($"\n{e.InnerException.Message}\n");
                }

                //ExceptionHandler.GenericExceptionHandler(Program.Exceptions, e, msg);
                throw;
            };
        }
Example #7
0
        public object Evaluate(object model = null, MemberRenamerDelegate memberRenamer = null, MemberFilterDelegate memberFilter = null)
        {
            var scriptObject = new ScriptObject();

            if (model != null)
            {
                scriptObject.Import(model, renamer: memberRenamer, filter: memberFilter);
            }

            var context = LexerOptions.Lang == ScriptLang.Liquid ? new LiquidTemplateContext() : new TemplateContext();

            context.EnableOutput  = false;
            context.MemberRenamer = memberRenamer;
            context.MemberFilter  = memberFilter;
            context.UseScientific = LexerOptions.Lang == ScriptLang.Scientific;
            context.PushGlobal(scriptObject);
            var result = Evaluate(context);

            context.PopGlobal();
            return(result);
        }
Example #8
0
        public async Task <FileResult> ScribanAsync()
        {
            var pathTemplate    = _configuration.GetValue <string>("Template:CatalogPdf");
            var templateContent = await System.IO.File.ReadAllTextAsync(pathTemplate);

            var template = Template.Parse(templateContent);

            var catalogPageModel = new CatalogPageFiltersViewModel()
            {
                Culture      = CultureInfo.CurrentCulture.Name,
                ItemsPerPage = 0
            };
            var catalogModel = await _catalogViewModelService.GetCatalogItems(catalogPageModel, false, true);

            var listCatalogItems = new List <CatalogItemViewModel>();

            foreach (var item in catalogModel.CatalogItems)
            {
                listCatalogItems.Add(
                    new CatalogItemViewModel()
                {
                    Name        = item.Name,
                    Price       = item.Price,
                    ShowPrice   = item.ShowPrice,
                    PriceSymbol = item.PriceSymbol,
                    PictureUri  = System.IO.Path.GetFullPath($"~{item.PictureUri}").Replace("~", "wwwroot")
                                  //PictureUri = "C:\\Formacao\\ASP.Net\\desenvolvimento\\eShopOnWeb\\src\\Web\\wwwroot\\images\\products\\1.png"
                }
                    );
            }

            MemberRenamerDelegate memberRenamer = member => member.Name;
            var pp   = new { Data = listCatalogItems, Date = DateTime.Now.ToString(), Year = DateTime.Now.Year  };
            var html = template.Render(pp, memberRenamer);

            var htmlToPdf = new HtmlToPdf();
            var pdf       = await htmlToPdf.RenderHtmlAsPdfAsync(html);

            return(File(pdf.BinaryData, "application/pdf;", "Catalog.pdf"));
        }
Example #9
0
        /// <summary>
        /// Evaluates the template using the specified context
        /// </summary>
        /// <param name="model">An object model to use with the evaluation.</param>
        /// <param name="memberRenamer">The member renamer used to import this .NET object and transitive objects. See member renamer documentation for more details.</param>
        /// <param name="memberFilter">The member filter used to filter members for .NET objects being accessed through the template, including the model being passed to this method.</param>
        /// <exception cref="System.InvalidOperationException">If the template <see cref="HasErrors"/>. Check the <see cref="Messages"/> property for more details</exception>
        /// <returns>Returns the result of the last statement</returns>
        public object Evaluate(object model = null, MemberRenamerDelegate memberRenamer = null, MemberFilterDelegate memberFilter = null)
        {
            var scriptObject = new ScriptObject();

            if (model != null)
            {
                scriptObject.Import(model, renamer: memberRenamer, filter: memberFilter);
            }

            var context = new TemplateContext
            {
                EnableOutput  = false,
                MemberRenamer = memberRenamer,
                MemberFilter  = memberFilter
            };

            context.PushGlobal(scriptObject);
            var result = Evaluate(context);

            context.PopGlobal();
            return(result);
        }
Example #10
0
        /// <summary>
        /// Catalog Item notify client
        /// </summary>
        /// <param name="email"></param>
        /// <param name="catalogItem"></param>
        /// <param name="priceNew"></param>
        /// <returns></returns>
        public async Task CatalogItemNotifyClient(string email, CatalogItem catalogItem, decimal priceNew)
        {
            var anyChanges = false;

            if (priceNew != catalogItem.Price)
            {
                anyChanges = true;
            }

            if (anyChanges)
            {
                MemberRenamerDelegate memberRenamer = member => member.Name;

                //email subject
                var subject = templateSubject.Render(new { CatalogItem = catalogItem  }, memberRenamer);

                //email message
                var message = templateBody.Render(
                    new { Greeting = greeting, PriceChanged = priceNew != catalogItem.Price }
                    );

                await _emailSender.SendEmailAsync(email, subject, message);
            }
        }
        /// <summary>
        /// Imports the specified object intto this <see cref="ScriptObject"/> context. See remarks.
        /// </summary>
        /// <param name="obj">The object.</param>
        /// <param name="filter">Optional member filterer</param>
        /// <param name="renamer">Optional renamer</param>
        /// <remarks>
        /// <ul>
        /// <li>If <paramref name="obj"/> is a <see cref="System.Type"/>, this method will import only the static field/properties of the specified object.</li>
        /// <li>If <paramref name="obj"/> is a <see cref="ScriptObject"/>, this method will import the members of the specified object into the new object.</li>
        /// <li>If <paramref name="obj"/> is a plain object, this method will import the public fields/properties of the specified object into the <see cref="ScriptObject"/>.</li>
        /// </ul>
        /// </remarks>
        public static void Import(this IScriptObject script, object obj, FilterMemberDelegate filter = null, MemberRenamerDelegate renamer = null)
        {
            if (obj is IScriptObject)
            {
                script.Import((IScriptObject)obj);
                return;
            }

            script.Import(obj, ScriptMemberImportFlags.All, filter, renamer);
        }
Example #12
0
 private static string ScribanRawParse(string template, dynamic model, MemberRenamerDelegate f = null) => Template.Parse(template).Render(model, f ?? ScribanCleanName);
Example #13
0
        public static void Import(this IScriptObject script, object obj, MemberFilterDelegate filter = null, MemberRenamerDelegate renamer = null)
        {
            if (obj is IScriptObject)
            {
                // TODO: Add support for filter, member renamer
                script.Import((IScriptObject)obj);
                return;
            }

            if (obj is IDictionary)
            {
                // TODO: Add support for filter, member renamer
                script.ImportDictionary((IDictionary)obj);
                return;
            }

            script.Import(obj, ScriptMemberImportFlags.All, filter, renamer);
        }
Example #14
0
        public static void Import(this IScriptObject script, object obj, ScriptMemberImportFlags flags, MemberFilterDelegate filter = null, MemberRenamerDelegate renamer = null)
        {
            if (obj == null)
            {
                return;
            }
            if (!ScriptObject.IsImportable(obj))
            {
                throw new ArgumentOutOfRangeException(nameof(obj), $"Unsupported object type `{obj.GetType()}`. Expecting plain class or struct");
            }

            var  typeInfo    = (obj as Type ?? obj.GetType());
            bool useStatic   = false;
            bool useInstance = false;

            if (obj is Type)
            {
                useStatic = true;
                obj       = null;
            }
            else
            {
                useInstance = true;
            }

            renamer = renamer ?? StandardMemberRenamer.Default;

            var typeToImports = new Stack <Type>();

            while (typeInfo != null)
            {
                typeToImports.Push(typeInfo);
                if (typeInfo.BaseType == typeof(object))
                {
                    break;
                }

                typeInfo = typeInfo.BaseType;
            }

            var scriptObj = script as ScriptObject;

            while (typeToImports.Count > 0)
            {
                typeInfo = typeToImports.Pop();

                if ((flags & ScriptMemberImportFlags.Field) != 0)
                {
                    foreach (var field in typeInfo.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly))
                    {
                        if (!field.IsPublic || field.IsLiteral)
                        {
                            continue;
                        }
                        if (filter != null && !filter(field))
                        {
                            continue;
                        }

                        var keep = field.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null;
                        if (keep && ((field.IsStatic && useStatic) || useInstance))
                        {
                            var newFieldName = renamer(field);
                            if (String.IsNullOrEmpty(newFieldName))
                            {
                                newFieldName = field.Name;
                            }

                            // If field is init only or literal, it cannot be set back so we mark it as read-only
                            if (scriptObj == null)
                            {
                                script.TrySetValue(null, new SourceSpan(), newFieldName, field.GetValue(obj), field.IsInitOnly || field.IsLiteral);
                            }
                            else
                            {
                                scriptObj.SetValue(newFieldName, field.GetValue(obj), field.IsInitOnly || field.IsLiteral);
                            }
                        }
                    }
                }

                if ((flags & ScriptMemberImportFlags.Property) != 0)
                {
                    foreach (var property in typeInfo.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly))
                    {
                        // Workaround with .NET Core, extension method is not working (retuning null despite doing property.GetMethod), so we need to inline it here
                        var getMethod = property.GetMethod;
                        if (!property.CanRead || !getMethod.IsPublic)
                        {
                            continue;
                        }

                        if (filter != null && !filter(property))
                        {
                            continue;
                        }

                        var keep = property.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null;
                        if (keep && (((getMethod.IsStatic && useStatic) || useInstance)))
                        {
                            var newPropertyName = renamer(property);
                            if (String.IsNullOrEmpty(newPropertyName))
                            {
                                newPropertyName = property.Name;
                            }

                            // Initially, we were setting readonly depending on the precense of a set method, but this is not compatible with liquid implems, so we remove readonly restriction
                            //script.SetValue(null, new SourceSpan(), newPropertyName, property.GetValue(obj), property.GetSetMethod() == null || !property.GetSetMethod().IsPublic);
                            if (scriptObj == null)
                            {
                                script.TrySetValue(null, new SourceSpan(), newPropertyName, property.GetValue(obj), false);
                            }
                            else
                            {
                                if (property.GetIndexParameters().Length == 0)
                                {
                                    scriptObj.SetValue(newPropertyName, property.GetValue(obj), false);
                                }
                            }
                        }
                    }
                }

                if ((flags & ScriptMemberImportFlags.Method) != 0 && useStatic)
                {
                    foreach (var method in typeInfo.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly))
                    {
                        if (filter != null && !filter(method))
                        {
                            continue;
                        }

                        var keep = method.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null;
                        if (keep && method.IsPublic && method.IsStatic && !method.IsSpecialName)
                        {
                            var newMethodName = renamer(method);
                            if (String.IsNullOrEmpty(newMethodName))
                            {
                                newMethodName = method.Name;
                            }

                            if (scriptObj == null)
                            {
                                script.TrySetValue(null, new SourceSpan(), newMethodName, DynamicCustomFunction.Create(obj, method), true);
                            }
                            else
                            {
                                scriptObj.SetValue(newMethodName, DynamicCustomFunction.Create(obj, method), true);
                            }
                        }
                    }
                }
            }
        }
Example #15
0
        /// <summary>
        /// Imports the specified object.
        /// </summary>
        /// <param name="obj">The object.</param>
        /// <param name="flags">The import flags.</param>
        /// <param name="filter">A filter applied on each member</param>
        /// <param name="renamer">The member renamer.</param>
        /// <exception cref="System.ArgumentOutOfRangeException"></exception>
        public static void Import(this IScriptObject script, object obj, ScriptMemberImportFlags flags, FilterMemberDelegate filter = null, MemberRenamerDelegate renamer = null)
        {
            if (obj == null)
            {
                return;
            }
            if (!ScriptObject.IsImportable(obj))
            {
                throw new ArgumentOutOfRangeException(nameof(obj), $"Unsupported object type [{obj.GetType()}]. Expecting plain class or struct");
            }

            var  typeInfo          = (obj as Type ?? obj.GetType()).GetTypeInfo();
            bool useStatic         = false;
            bool useInstance       = false;
            bool useMethodInstance = false;

            if (obj is Type)
            {
                useStatic = true;
                obj       = null;
            }
            else
            {
                useInstance       = true;
                useMethodInstance = (flags & ScriptMemberImportFlags.MethodInstance) != 0;
            }

            renamer = renamer ?? StandardMemberRenamer.Default;

            if ((flags & ScriptMemberImportFlags.Field) != 0)
            {
                foreach (var field in typeInfo.GetDeclaredFields())
                {
                    if (!field.IsPublic)
                    {
                        continue;
                    }
                    if (filter != null && !filter(field.Name))
                    {
                        continue;
                    }

                    var keep = field.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null;
                    if (keep && ((field.IsStatic && useStatic) || useInstance))
                    {
                        var newFieldName = renamer(field.Name);
                        if (String.IsNullOrEmpty(newFieldName))
                        {
                            newFieldName = field.Name;
                        }

                        // If field is init only or literal, it cannot be set back so we mark it as read-only
                        script.SetValue(null, new SourceSpan(), newFieldName, field.GetValue(obj), field.IsInitOnly || field.IsLiteral);
                    }
                }
            }

            if ((flags & ScriptMemberImportFlags.Property) != 0)
            {
                foreach (var property in typeInfo.GetDeclaredProperties())
                {
                    if (!property.CanRead || !property.GetGetMethod().IsPublic)
                    {
                        continue;
                    }

                    if (filter != null && !filter(property.Name))
                    {
                        continue;
                    }

                    var keep = property.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null;
                    if (keep && (((property.GetGetMethod().IsStatic&& useStatic) || useInstance)))
                    {
                        var newPropertyName = renamer(property.Name);
                        if (String.IsNullOrEmpty(newPropertyName))
                        {
                            newPropertyName = property.Name;
                        }

                        script.SetValue(null, new SourceSpan(), newPropertyName, property.GetValue(obj), property.GetSetMethod() == null || !property.GetSetMethod().IsPublic);
                    }
                }
            }

            if ((flags & ScriptMemberImportFlags.Method) != 0 && (useStatic || useMethodInstance))
            {
                foreach (var method in typeInfo.GetDeclaredMethods())
                {
                    if (filter != null && !filter(method.Name))
                    {
                        continue;
                    }

                    var keep = method.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null;
                    if (keep && method.IsPublic && ((useMethodInstance && !method.IsStatic) || (useStatic && method.IsStatic)) && !method.IsSpecialName)
                    {
                        var newMethodName = renamer(method.Name);
                        if (String.IsNullOrEmpty(newMethodName))
                        {
                            newMethodName = method.Name;
                        }

                        script.SetValue(null, new SourceSpan(), newMethodName, new ObjectFunctionWrapper(obj, method), true);
                    }
                }
            }
        }
Example #16
0
 private static List <Scriban.Parsing.LogMessage> ScribanErrors(string template, dynamic model, MemberRenamerDelegate f = null) => Template.Parse(template).Messages;
Example #17
0
        /// <summary>
        /// Imports the specified object.
        /// </summary>
        /// <param name="scriptObject">The script object to import into</param>
        /// <param name="obj">The object.</param>
        /// <param name="flags">The import flags.</param>
        /// <param name="filter">A filter applied on each member</param>
        /// <param name="renamer">The member renamer.</param>
        /// <exception cref="ArgumentOutOfRangeException">The object is not importable.</exception>
        public static void Import(this IScriptObject scriptObject, object obj, ScriptMemberImportFlags flags, MemberFilterDelegate filter = null, MemberRenamerDelegate renamer = null)
        {
            if (obj == null)
            {
                return;
            }

            if (!ScriptObject.IsImportable(obj))
            {
                throw new ArgumentOutOfRangeException(nameof(obj), string.Format(RS.InvalidObjectType, obj.GetType()));
            }

#if NETSTANDARD
            TypeInfo typeInfo = (obj as Type ?? obj.GetType()).GetTypeInfo();
#else
            Type typeInfo = (obj as Type ?? obj.GetType()).GetTypeInfo();
#endif

            bool useStatic   = false;
            bool useInstance = false;
            if (obj is Type)
            {
                useStatic = true;
                obj       = null;
            }
            else
            {
                useInstance = true;
            }

            renamer = renamer ?? StandardMemberRenamer.Default;

            while (typeInfo != null)
            {
                if ((flags & ScriptMemberImportFlags.Field) != 0)
                {
                    foreach (FieldInfo field in typeInfo.GetDeclaredFields())
                    {
                        if (!field.IsPublic)
                        {
                            continue;
                        }
                        if (filter != null && !filter(field))
                        {
                            continue;
                        }

                        bool keep = field.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null;
                        if (keep && ((field.IsStatic && useStatic) || useInstance))
                        {
                            string newFieldName = renamer(field);
                            if (string.IsNullOrEmpty(newFieldName))
                            {
                                newFieldName = field.Name;
                            }

                            // If field is init only or literal, it cannot be set back so we mark it as read-only
                            scriptObject.SetValue(null, new SourceSpan(), newFieldName, field.GetValue(obj), field.IsInitOnly || field.IsLiteral);
                        }
                    }
                }

                if ((flags & ScriptMemberImportFlags.Property) != 0)
                {
                    foreach (PropertyInfo property in typeInfo.GetDeclaredProperties())
                    {
                        // Workaround with .NET Core, extension method is not working (retuning null)
#if NETFX
                        MethodInfo getMethod = property.GetGetMethod();
#else
                        MethodInfo getMethod = property.GetMethod;
#endif

                        if (!property.CanRead || !getMethod.IsPublic)
                        {
                            continue;
                        }

                        if (filter != null && !filter(property))
                        {
                            continue;
                        }

                        bool keep = property.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null;
                        if (keep && ((getMethod.IsStatic && useStatic) || useInstance))
                        {
                            string newPropertyName = renamer(property);
                            if (string.IsNullOrEmpty(newPropertyName))
                            {
                                newPropertyName = property.Name;
                            }

                            // Initially, we were setting readonly depending on the precense of a set method, but this is not compatible with liquid implems, so we remove readonly restriction
                            //script.SetValue(null, new SourceSpan(), newPropertyName, property.GetValue(obj), property.GetSetMethod() == null || !property.GetSetMethod().IsPublic);
                            scriptObject.SetValue(null, new SourceSpan(), newPropertyName, property.GetValue(obj), false);
                        }
                    }
                }

                if ((flags & ScriptMemberImportFlags.Method) != 0 && useStatic)
                {
                    foreach (MethodInfo method in typeInfo.GetDeclaredMethods())
                    {
                        if (filter != null && !filter(method))
                        {
                            continue;
                        }

                        bool keep = method.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null;
                        if (keep && method.IsPublic && method.IsStatic && !method.IsSpecialName)
                        {
                            string newMethodName = renamer(method);
                            if (string.IsNullOrEmpty(newMethodName))
                            {
                                newMethodName = method.Name;
                            }

                            scriptObject.SetValue(null, new SourceSpan(), newMethodName, DynamicCustomFunction.Create(obj, method), true);
                        }
                    }
                }

                if (typeInfo.BaseType == typeof(object))
                {
                    break;
                }

                typeInfo = typeInfo.BaseType.GetTypeInfo();
            }
        }
        /// <summary>
        /// Imports the specified object.
        /// </summary>
        /// <param name="script">The script object to import into</param>
        /// <param name="obj">The object.</param>
        /// <param name="flags">The import flags.</param>
        /// <param name="filter">A filter applied on each member</param>
        /// <param name="renamer">The member renamer.</param>
        /// <exception cref="System.ArgumentOutOfRangeException"></exception>
        public static void Import(this IScriptObject script, object obj, ScriptMemberImportFlags flags, MemberFilterDelegate filter = null, MemberRenamerDelegate renamer = null)
        {
            if (obj == null)
            {
                return;
            }
            if (!ScriptObject.IsImportable(obj))
            {
                throw new ArgumentOutOfRangeException(nameof(obj), $"Unsupported object type `{obj.GetType()}`. Expecting plain class or struct");
            }

            var  typeInfo    = (obj as Type ?? obj.GetType()).GetTypeInfo();
            bool useStatic   = false;
            bool useInstance = false;

            if (obj is Type)
            {
                useStatic = true;
                obj       = null;
            }
            else
            {
                useInstance = true;
            }

            renamer = renamer ?? StandardMemberRenamer.Default;

            while (typeInfo != null)
            {
                if ((flags & ScriptMemberImportFlags.Field) != 0)
                {
                    foreach (var field in typeInfo.GetDeclaredFields())
                    {
                        if (!field.IsPublic)
                        {
                            continue;
                        }
                        if (filter != null && !filter(field))
                        {
                            continue;
                        }

                        var keep = field.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null;
                        if (keep && ((field.IsStatic && useStatic) || useInstance))
                        {
                            var newFieldName = renamer(field);
                            if (String.IsNullOrEmpty(newFieldName))
                            {
                                newFieldName = field.Name;
                            }

                            // If field is init only or literal, it cannot be set back so we mark it as read-only
                            script.SetValue(null, new SourceSpan(), newFieldName, field.GetValue(obj), field.IsInitOnly || field.IsLiteral);
                        }
                    }
                }

                if ((flags & ScriptMemberImportFlags.Property) != 0)
                {
                    foreach (var property in typeInfo.GetDeclaredProperties())
                    {
                        var methodInfoReadProperty = property.GetGetMethod();
                        if (methodInfoReadProperty is null)
                        {
                            continue;
                        }
                        if (!property.CanRead || !methodInfoReadProperty.IsPublic)
                        {
                            continue;
                        }

                        if (filter != null && !filter(property))
                        {
                            continue;
                        }

                        var keep = property.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null;
                        if (keep && (((methodInfoReadProperty.IsStatic && useStatic) || useInstance)))
                        {
                            var newPropertyName = renamer(property);
                            if (String.IsNullOrEmpty(newPropertyName))
                            {
                                newPropertyName = property.Name;
                            }

                            // Initially, we were setting readonly depending on the precense of a set method, but this is not compatible with liquid implems, so we remove readonly restriction
                            //script.SetValue(null, new SourceSpan(), newPropertyName, property.GetValue(obj), property.GetSetMethod() == null || !property.GetSetMethod().IsPublic);
                            script.SetValue(null, new SourceSpan(), newPropertyName, property.GetValue(obj), false);
                        }
                    }
                }

                if ((flags & ScriptMemberImportFlags.Method) != 0 && useStatic)
                {
                    foreach (var method in typeInfo.GetDeclaredMethods())
                    {
                        if (filter != null && !filter(method))
                        {
                            continue;
                        }

                        var keep = method.GetCustomAttribute <ScriptMemberIgnoreAttribute>() == null;
                        if (keep && method.IsPublic && method.IsStatic && !method.IsSpecialName)
                        {
                            var newMethodName = renamer(method);
                            if (String.IsNullOrEmpty(newMethodName))
                            {
                                newMethodName = method.Name;
                            }

                            script.SetValue(null, new SourceSpan(), newMethodName, DynamicCustomFunction.Create(obj, method), true);
                        }
                    }
                }

                if (typeInfo.BaseType == typeof(object))
                {
                    break;
                }
                typeInfo = typeInfo.BaseType.GetTypeInfo();
            }
        }
Example #19
0
 public TypedObjectAccessor(Type targetType, MemberFilterDelegate filter, MemberRenamerDelegate renamer) : this(targetType, null, filter, renamer)
 {
 }