Example #1
0
        private bool CheckGenericTypeForMatch(Type typeToFormat, MorestachioFormatterModel formatTemplateElement)
        {
            var typeToFormatGenerics = typeToFormat.GetTypeInfo().GetGenericArguments();

            //explicit check for array support
            if (typeToFormat.HasElementType)
            {
                var elementType = typeToFormat.GetElementType();
                typeToFormatGenerics = typeToFormatGenerics.Concat(new[]
                {
                    elementType
                }).ToArray();
            }

            //the type check has maybe failed because of generic parameter. Check if both the formatter and the typ have generic arguments

            var formatterGenerics = formatTemplateElement.InputType.GetTypeInfo().GetGenericArguments();

            if (typeToFormatGenerics.Length <= 0 || formatterGenerics.Length <= 0 ||
                typeToFormatGenerics.Length != formatterGenerics.Length)
            {
                return(false);
            }

            return(true);
        }
Example #2
0
        /// <inheritdoc />
        public virtual MorestachioFormatterModel Add(MethodInfo method,
                                                     MorestachioFormatterAttribute morestachioFormatterAttribute)
        {
            morestachioFormatterAttribute.ValidateFormatter(method);
            var arguments = morestachioFormatterAttribute.GetParameters(method);

            var name = morestachioFormatterAttribute.GetFormatterName(method);;
            var morestachioFormatterModel = new MorestachioFormatterModel(name,
                                                                          morestachioFormatterAttribute.Description,
                                                                          arguments.FirstOrDefault(e => e.IsSourceObject)?.ParameterType ?? typeof(object),
                                                                          morestachioFormatterAttribute.OutputType ?? method.ReturnType,
                                                                          method.GetCustomAttributes <MorestachioFormatterInputAttribute>()
                                                                          .Select(e => new InputDescription(e.Description, e.OutputType, e.Example)).ToArray(),
                                                                          morestachioFormatterAttribute.ReturnHint,
                                                                          method,
                                                                          new MultiFormatterInfoCollection(arguments),
                                                                          !morestachioFormatterAttribute.IsSourceObjectAware,
                                                                          morestachioFormatterAttribute.LinkFunctionTarget);

            name = name ?? "{NULL}";

            if (!Formatters.TryGetValue(name, out var formatters))
            {
                formatters       = new List <MorestachioFormatterModel>();
                Formatters[name] = formatters;
            }

            formatters.Add(morestachioFormatterModel);
            return(morestachioFormatterModel);
        }
Example #3
0
        /// <summary>
        ///     Composes the values into a Dictionary for each formatter. If returns null, the formatter will not be called.
        /// </summary>
        public virtual FormatterComposingResult ComposeValues(
            [NotNull] MorestachioFormatterModel formatter,
            [CanBeNull] object sourceObject,
            [NotNull] MethodInfo method,
            [NotNull] params KeyValuePair <string, object>[] templateArguments)
        {
            Log(() =>
                $"Compose values for object '{sourceObject}' with formatter '{formatter.InputType}' targets '{formatter.Function.Name}'");
            var values  = new Dictionary <MultiFormatterInfo, object>();
            var matched = new Dictionary <MultiFormatterInfo, Tuple <string, object> >();

            var templateArgumentsQueue = templateArguments.Select(e => Tuple.Create(e.Key, e.Value)).ToList();

            var argumentIndex = 0;

            foreach (var parameter in formatter.MetaData.Where(e => !e.IsRestObject))
            {
                argumentIndex++;
                Log(() => $"Match parameter '{parameter.ParameterType}' [{parameter.Name}]");
                object givenValue;
                //set ether the source object or the value from the given arguments

                if (parameter.IsSourceObject)
                {
                    Log(() => "Is Source object");
                    givenValue = sourceObject;
                }
                else
                {
                    //match by index or name
                    Log(() => "Try Match by Name");
                    //match by name
                    var match = templateArgumentsQueue.FirstOrDefault(e =>
                                                                      !string.IsNullOrWhiteSpace(e.Item1) && e.Item1.Equals(parameter.Name));

                    if (match == null)
                    {
                        Log(() => "Try Match by Index");
                        //match by index
                        var index = 0;
                        match = templateArgumentsQueue.FirstOrDefault(g => index++ == parameter.Index);
                    }

                    if (match == null)
                    {
                        if (parameter.IsOptional)
                        {
                            givenValue = null;
                            match      = new Tuple <string, object>(parameter.Name, null);
                        }
                        else
                        {
                            Log(() => $"Skip: Could not match the parameter at index '{parameter.Index}' nether by name nor by index");
                            return(default);
Example #4
0
        /// <summary>
        ///     Executes the specified formatter.
        /// </summary>
        /// <param name="formatter">The formatter.</param>
        /// <param name="sourceObject">The source object.</param>
        /// <param name="templateArguments">The template arguments.</param>
        /// <returns></returns>
        public virtual async Task <object> Execute(MorestachioFormatterModel formatter,
                                                   object sourceObject,
                                                   params KeyValuePair <string, object>[] templateArguments)
        {
            var values = ComposeValues(formatter, sourceObject, formatter.Function, templateArguments);

            if (values.Equals(new FormatterComposingResult()))
            {
                Log(() => "Skip: Execute skip as Compose Values returned an invalid value");
                return(FormatterFlow.Skip);
            }

            Log(() => "Execute");
            var taskAlike = values.MethodInfo.Invoke(formatter.FunctionTarget, values.Arguments.Select(e => e.Value).ToArray());

            return(await taskAlike.UnpackFormatterTask());
        }
Example #5
0
        /// <summary>
        ///     Composes the values into a Dictionary for each formatter. If returns null, the formatter will not be called.
        /// </summary>
        public virtual FormatterComposingResult ComposeValues([NotNull] MorestachioFormatterModel formatter,
                                                              [CanBeNull] object sourceObject,
                                                              [NotNull] MethodInfo method,
                                                              [NotNull] ServiceCollection services,
                                                              [NotNull] params KeyValuePair <string, object>[] templateArguments)
        {
            Log(() =>
                $"Compose values for object '{sourceObject}' with formatter '{formatter.InputType}' targets '{formatter.Function.Name}'");
            var values  = new Dictionary <MultiFormatterInfo, object>();
            var matched = new Dictionary <MultiFormatterInfo, Tuple <string, object> >();

            var templateArgumentsQueue = templateArguments.Select(e => Tuple.Create(e.Key, e.Value)).ToList();

            var argumentIndex = 0;

            foreach (var parameter in formatter.MetaData.Where(e => !e.IsRestObject))
            {
                argumentIndex++;
                Log(() => $"Match parameter '{parameter.ParameterType}' [{parameter.Name}]");
                object givenValue;
                //set ether the source object or the value from the given arguments

                if (parameter.IsSourceObject)
                {
                    Log(() => "Is Source object");
                    givenValue = sourceObject;
                }
                else if (parameter.IsInjected)
                {
                    //match by index or name
                    Log(() => "Get the injected service");
                    if (services.GetService(parameter.ParameterType, out var service))
                    {
                        if (service is Delegate factory)
                        {
                            service = factory.DynamicInvoke();
                        }

                        givenValue = service;

                        if (!parameter.ParameterType.IsInstanceOfType(givenValue))
                        {
                            Log(() => $"Expected service of type '{parameter.ParameterType}' but got '{givenValue}'");
                            return(default);
Example #6
0
        /// <summary>
        ///     Composes the values into a Dictionary for each formatter. If returns null, the formatter will not be called.
        /// </summary>
        public virtual PrepareFormatterComposingResult PrepareComposeValues(MorestachioFormatterModel formatter,
                                                                            Type sourceType,
                                                                            MethodInfo method,
                                                                            ServiceCollection services,
                                                                            FormatterArgumentType[] templateArguments,
                                                                            ParserOptions parserOptions)
        {
            Log(parserOptions, () =>
                $"Compose values for object '{sourceType}' with formatter '{formatter.InputType}' targets '{formatter.Function.Name}'");

            var matched = new Dictionary <MultiFormatterInfo, FormatterArgumentMap>();

            for (var i = 0; i < formatter.MetaData.NonParamsArguments.Count; i++)
            {
                var parameter = formatter.MetaData.NonParamsArguments[i];
                Log(parserOptions, () => $"Match parameter '{parameter.ParameterType}' [{parameter.Name}]");

                //set ether the source object or the value from the given arguments

                FormatterArgumentType match;
                if (parameter.IsSourceObject)
                {
                    Log(parserOptions, () => "Is Source object");

                    matched[parameter] = new FormatterArgumentMap(i, null)
                    {
                        ObtainValue = (source, args) => source
                    };
                    match = new FormatterArgumentType(i, (string)null, sourceType);
                }
                else
                {
                    if (parameter.IsInjected)
                    {
                        //match by index or name
                        Log(parserOptions, () => "Get the injected service");
                        if (services.TryGetService(parameter.ParameterType, out var service))
                        {
                            if (!parameter.ParameterType.IsInstanceOfType(service))
                            {
                                Log(parserOptions, () => $"Expected service of type '{parameter.ParameterType}' but got '{service}'");
                                return(default);
Example #7
0
        /// <summary>
        ///		Adds all formatter that are decorated with the <see cref="MorestachioFormatterAttribute"/>
        /// </summary>
        /// <param name="type">The type.</param>
        public void AddFromType(Type type)
        {
            foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Public))
            {
                var hasFormatterAttr = method.GetCustomAttributes <MorestachioFormatterAttribute>();
                foreach (var morestachioFormatterAttribute in hasFormatterAttr)
                {
                    if (morestachioFormatterAttribute == null)
                    {
                        continue;
                    }

                    var morestachioFormatterModel = new MorestachioFormatterModel(morestachioFormatterAttribute.Name, morestachioFormatterAttribute.Description,
                                                                                  method.GetParameters().FirstOrDefault()?.ParameterType,
                                                                                  morestachioFormatterAttribute.OutputType ?? method.ReturnType,
                                                                                  method.GetCustomAttributes <MorestachioFormatterInputAttribute>().Select(e => new InputDescription(e.Description, e.OutputType, e.Example)).ToArray(),
                                                                                  morestachioFormatterAttribute.ReturnHint, method);
                    GlobalFormatterModels.Add(morestachioFormatterModel);
                }
            }
        }