Example #1
0
        private Task GenerateMultipleFileAsync(string output, string resolverName, ObjectSerializationInfo[] objectInfo, EnumSerializationInfo[] enumInfo, UnionSerializationInfo[] unionInfo, string namespaceDot, string multioutSymbol, GenericSerializationInfo[] genericInfo)
        {
            string GetNamespace(INamespaceInfo x)
            {
                if (x.Namespace == null)
                {
                    return(namespaceDot + "Formatters");
                }

                return(namespaceDot + "Formatters." + x.Namespace);
            }

            var waitingTasks = new Task[objectInfo.Length + enumInfo.Length + unionInfo.Length + 1];
            var waitingIndex = 0;

            foreach (var x in objectInfo)
            {
                var ns       = namespaceDot + "Formatters" + (x.Namespace is null ? string.Empty : "." + x.Namespace);
                var template = x.IsStringKey ? new StringKeyFormatterTemplate(ns, new[] { x }) : (IFormatterTemplate) new FormatterTemplate(ns, new[] { x });
                var text     = template.TransformText();
                waitingTasks[waitingIndex++] = OutputToDirAsync(output, template.Namespace, x.Name + "Formatter", multioutSymbol, text);
            }

            foreach (var x in enumInfo)
            {
                var template = new EnumTemplate(GetNamespace(x), new[] { x });
                var text     = template.TransformText();
                waitingTasks[waitingIndex++] = OutputToDirAsync(output, template.Namespace, x.Name + "Formatter", multioutSymbol, text);
            }

            foreach (var x in unionInfo)
            {
                var template = new UnionTemplate(GetNamespace(x), new[] { x });
                var text     = template.TransformText();
                waitingTasks[waitingIndex++] = OutputToDirAsync(output, template.Namespace, x.Name + "Formatter", multioutSymbol, text);
            }

            var resolverTemplate = new ResolverTemplate(namespaceDot + "Resolvers", namespaceDot + "Formatters", resolverName, genericInfo.Where(x => !x.IsOpenGenericType).Cast <IResolverRegisterInfo>().Concat(enumInfo).Concat(unionInfo).Concat(objectInfo.Where(x => !x.IsOpenGenericType)).ToArray());

            waitingTasks[waitingIndex] = OutputToDirAsync(output, resolverTemplate.Namespace, resolverTemplate.ResolverName, multioutSymbol, resolverTemplate.TransformText());
            return(Task.WhenAll(waitingTasks));
        }
Example #2
0
        public async Task GenerateFileAsync(
            string input,
            string output,
            string conditionalSymbol,
            string resolverName,
            string @namespace,
            bool useMapMode,
            string multipleIfDirectiveOutputSymbols)
        {
            var namespaceDot          = string.IsNullOrWhiteSpace(@namespace) ? string.Empty : @namespace + ".";
            var conditionalSymbols    = conditionalSymbol?.Split(',') ?? Array.Empty <string>();
            var multipleOutputSymbols = multipleIfDirectiveOutputSymbols?.Split(',') ?? Array.Empty <string>();

            var sw = Stopwatch.StartNew();

            foreach (var multioutSymbol in multipleOutputSymbols.Length == 0 ? new[] { string.Empty } : multipleOutputSymbols)
            {
                logger("Project Compilation Start:" + input);

                var compilation = (Path.GetExtension(input) == ".csproj")
                    ? await MessagePackCompilation.CreateFromProjectAsync(input.Split(','), conditionalSymbols.Concat(new[] { multioutSymbol }).ToArray(), cancellationToken)
                                  .ConfigureAwait(false) : await MessagePackCompilation.CreateFromDirectoryAsync(input, conditionalSymbols.Concat(new[] { multioutSymbol }).ToArray(), cancellationToken).ConfigureAwait(false);

                var collector = new TypeCollector(compilation, true, useMapMode, x => Console.WriteLine(x));

                logger("Project Compilation Complete:" + sw.Elapsed.ToString());

                sw.Restart();
                logger("Method Collect Start");

                var(objectInfo, enumInfo, genericInfo, unionInfo) = collector.Collect();

                logger("Method Collect Complete:" + sw.Elapsed.ToString());

                logger("Output Generation Start");
                sw.Restart();

                if (Path.GetExtension(output) == ".cs")
                {
                    // SingleFile Output
                    var objectFormatterTemplates = objectInfo
                                                   .GroupBy(x => x.Namespace)
                                                   .Select(x => new FormatterTemplate()
                    {
                        Namespace = namespaceDot + "Formatters" + ((x.Key == null) ? string.Empty : "." + x.Key),
                        ObjectSerializationInfos = x.ToArray(),
                    })
                                                   .ToArray();

                    var enumFormatterTemplates = enumInfo
                                                 .GroupBy(x => x.Namespace)
                                                 .Select(x => new EnumTemplate()
                    {
                        Namespace = namespaceDot + "Formatters" + ((x.Key == null) ? string.Empty : "." + x.Key),
                        EnumSerializationInfos = x.ToArray(),
                    })
                                                 .ToArray();

                    var unionFormatterTemplates = unionInfo
                                                  .GroupBy(x => x.Namespace)
                                                  .Select(x => new UnionTemplate()
                    {
                        Namespace = namespaceDot + "Formatters" + ((x.Key == null) ? string.Empty : "." + x.Key),
                        UnionSerializationInfos = x.ToArray(),
                    })
                                                  .ToArray();

                    var resolverTemplate = new ResolverTemplate()
                    {
                        Namespace          = namespaceDot + "Resolvers",
                        FormatterNamespace = namespaceDot + "Formatters",
                        ResolverName       = resolverName,
                        RegisterInfos      = genericInfo.Cast <IResolverRegisterInfo>().Concat(enumInfo).Concat(unionInfo).Concat(objectInfo).ToArray(),
                    };

                    var sb = new StringBuilder();
                    sb.AppendLine(resolverTemplate.TransformText());
                    sb.AppendLine();
                    foreach (var item in enumFormatterTemplates)
                    {
                        var text = item.TransformText();
                        sb.AppendLine(text);
                    }

                    sb.AppendLine();
                    foreach (var item in unionFormatterTemplates)
                    {
                        var text = item.TransformText();
                        sb.AppendLine(text);
                    }

                    sb.AppendLine();
                    foreach (var item in objectFormatterTemplates)
                    {
                        var text = item.TransformText();
                        sb.AppendLine(text);
                    }

                    if (multioutSymbol == string.Empty)
                    {
                        await OutputAsync(output, sb.ToString(), cancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        var fname = Path.GetFileNameWithoutExtension(output) + "." + MultiSymbolToSafeFilePath(multioutSymbol) + ".cs";
                        var text  = $"#if {multioutSymbol}" + Environment.NewLine + sb.ToString() + Environment.NewLine + "#endif";
                        await OutputAsync(Path.Combine(Path.GetDirectoryName(output), fname), text, cancellationToken).ConfigureAwait(false);
                    }
                }
                else
                {
                    // Multiple File output
                    foreach (var x in objectInfo)
                    {
                        var template = new FormatterTemplate()
                        {
                            Namespace = namespaceDot + "Formatters" + ((x.Namespace == null) ? string.Empty : "." + x.Namespace),
                            ObjectSerializationInfos = new[] { x },
                        };

                        var text = template.TransformText();
                        await OutputToDirAsync(output, template.Namespace, x.Name + "Formatter", multioutSymbol, text, cancellationToken).ConfigureAwait(false);
                    }

                    foreach (var x in enumInfo)
                    {
                        var template = new EnumTemplate()
                        {
                            Namespace = namespaceDot + "Formatters" + ((x.Namespace == null) ? string.Empty : "." + x.Namespace),
                            EnumSerializationInfos = new[] { x },
                        };

                        var text = template.TransformText();
                        await OutputToDirAsync(output, template.Namespace, x.Name + "Formatter", multioutSymbol, text, cancellationToken).ConfigureAwait(false);
                    }

                    foreach (var x in unionInfo)
                    {
                        var template = new UnionTemplate()
                        {
                            Namespace = namespaceDot + "Formatters" + ((x.Namespace == null) ? string.Empty : "." + x.Namespace),
                            UnionSerializationInfos = new[] { x },
                        };

                        var text = template.TransformText();
                        await OutputToDirAsync(output, template.Namespace, x.Name + "Formatter", multioutSymbol, text, cancellationToken).ConfigureAwait(false);
                    }

                    var resolverTemplate = new ResolverTemplate()
                    {
                        Namespace          = namespaceDot + "Resolvers",
                        FormatterNamespace = namespaceDot + "Formatters",
                        ResolverName       = resolverName,
                        RegisterInfos      = genericInfo.Cast <IResolverRegisterInfo>().Concat(enumInfo).Concat(unionInfo).Concat(objectInfo).ToArray(),
                    };

                    await OutputToDirAsync(output, resolverTemplate.Namespace, resolverTemplate.ResolverName, multioutSymbol, resolverTemplate.TransformText(), cancellationToken).ConfigureAwait(false);
                }
            }

            logger("Output Generation Complete:" + sw.Elapsed.ToString());
        }
        /// <summary>
        /// Generates the specialized resolver and formatters for the types that require serialization in a given compilation.
        /// </summary>
        /// <param name="compilation">The compilation to read types from as an input to code generation.</param>
        /// <param name="output">The name of the generated source file.</param>
        /// <param name="resolverName">The resolver name.</param>
        /// <param name="namespace">The namespace for the generated type to be created in. May be null.</param>
        /// <param name="useMapMode">A boolean value that indicates whether all formatters should use property maps instead of more compact arrays.</param>
        /// <param name="multipleIfDirectiveOutputSymbols">A comma-delimited list of symbols that should surround redundant generated files. May be null.</param>
        /// <param name="externalIgnoreTypeNames"> May be null.</param>
        /// <returns>A task that indicates when generation has completed.</returns>
        public async Task GenerateFileAsync(
            Compilation compilation,
            string output,
            string resolverName,
            string @namespace,
            bool useMapMode,
            string multipleIfDirectiveOutputSymbols,
            string[] externalIgnoreTypeNames)
        {
            var namespaceDot          = string.IsNullOrWhiteSpace(@namespace) ? string.Empty : @namespace + ".";
            var multipleOutputSymbols = multipleIfDirectiveOutputSymbols?.Split(',') ?? Array.Empty <string>();

            var sw = Stopwatch.StartNew();

            foreach (var multioutSymbol in multipleOutputSymbols.Length == 0 ? new[] { string.Empty } : multipleOutputSymbols)
            {
                logger("Project Compilation Start:" + compilation.AssemblyName);

                var collector = new TypeCollector(compilation, true, useMapMode, externalIgnoreTypeNames, x => Console.WriteLine(x));

                logger("Project Compilation Complete:" + sw.Elapsed.ToString());

                sw.Restart();
                logger("Method Collect Start");

                var(objectInfo, enumInfo, genericInfo, unionInfo) = collector.Collect();

                logger("Method Collect Complete:" + sw.Elapsed.ToString());

                logger("Output Generation Start");
                sw.Restart();

                if (Path.GetExtension(output) == ".cs")
                {
                    // SingleFile Output
                    var objectFormatterTemplates = objectInfo
                                                   .GroupBy(x => (x.Namespace, x.IsStringKey))
                                                   .Select(x =>
                    {
                        var(nameSpace, isStringKey)  = x.Key;
                        var objectSerializationInfos = x.ToArray();
                        var template = isStringKey ? new StringKeyFormatterTemplate() : (IFormatterTemplate) new FormatterTemplate();

                        template.Namespace = namespaceDot + "Formatters" + (nameSpace is null ? string.Empty : "." + nameSpace);
                        template.ObjectSerializationInfos = objectSerializationInfos;

                        return(template);
                    })
                                                   .ToArray();

                    var enumFormatterTemplates = enumInfo
                                                 .GroupBy(x => x.Namespace)
                                                 .Select(x => new EnumTemplate()
                    {
                        Namespace = namespaceDot + "Formatters" + ((x.Key == null) ? string.Empty : "." + x.Key),
                        EnumSerializationInfos = x.ToArray(),
                    })
                                                 .ToArray();

                    var unionFormatterTemplates = unionInfo
                                                  .GroupBy(x => x.Namespace)
                                                  .Select(x => new UnionTemplate()
                    {
                        Namespace = namespaceDot + "Formatters" + ((x.Key == null) ? string.Empty : "." + x.Key),
                        UnionSerializationInfos = x.ToArray(),
                    })
                                                  .ToArray();

                    var resolverTemplate = new ResolverTemplate()
                    {
                        Namespace          = namespaceDot + "Resolvers",
                        FormatterNamespace = namespaceDot + "Formatters",
                        ResolverName       = resolverName,
                        RegisterInfos      = genericInfo.Where(x => !x.IsOpenGenericType).Cast <IResolverRegisterInfo>().Concat(enumInfo).Concat(unionInfo).Concat(objectInfo.Where(x => !x.IsOpenGenericType)).ToArray(),
                    };

                    var sb = new StringBuilder();
                    sb.AppendLine(resolverTemplate.TransformText());
                    sb.AppendLine();
                    foreach (var item in enumFormatterTemplates)
                    {
                        var text = item.TransformText();
                        sb.AppendLine(text);
                    }

                    sb.AppendLine();
                    foreach (var item in unionFormatterTemplates)
                    {
                        var text = item.TransformText();
                        sb.AppendLine(text);
                    }

                    sb.AppendLine();
                    foreach (var item in objectFormatterTemplates)
                    {
                        var text = item.TransformText();
                        sb.AppendLine(text);
                    }

                    if (multioutSymbol == string.Empty)
                    {
                        await OutputAsync(output, sb.ToString(), cancellationToken);
                    }
                    else
                    {
                        var fname = Path.GetFileNameWithoutExtension(output) + "." + MultiSymbolToSafeFilePath(multioutSymbol) + ".cs";
                        var text  = $"#if {multioutSymbol}" + Environment.NewLine + sb.ToString() + Environment.NewLine + "#endif";
                        await OutputAsync(Path.Combine(Path.GetDirectoryName(output), fname), text, cancellationToken);
                    }
                }
                else
                {
                    // Multiple File output
                    foreach (var x in objectInfo)
                    {
                        var template = x.IsStringKey ? new StringKeyFormatterTemplate() : (IFormatterTemplate) new FormatterTemplate();
                        template.Namespace = namespaceDot + "Formatters" + (x.Namespace is null ? string.Empty : "." + x.Namespace);
                        template.ObjectSerializationInfos = new[] { x };

                        var text = template.TransformText();
                        await OutputToDirAsync(output, template.Namespace, x.Name + "Formatter", multioutSymbol, text, cancellationToken);
                    }

                    foreach (var x in enumInfo)
                    {
                        var template = new EnumTemplate()
                        {
                            Namespace = namespaceDot + "Formatters" + ((x.Namespace == null) ? string.Empty : "." + x.Namespace),
                            EnumSerializationInfos = new[] { x },
                        };

                        var text = template.TransformText();
                        await OutputToDirAsync(output, template.Namespace, x.Name + "Formatter", multioutSymbol, text, cancellationToken);
                    }

                    foreach (var x in unionInfo)
                    {
                        var template = new UnionTemplate()
                        {
                            Namespace = namespaceDot + "Formatters" + ((x.Namespace == null) ? string.Empty : "." + x.Namespace),
                            UnionSerializationInfos = new[] { x },
                        };

                        var text = template.TransformText();
                        await OutputToDirAsync(output, template.Namespace, x.Name + "Formatter", multioutSymbol, text, cancellationToken);
                    }

                    var resolverTemplate = new ResolverTemplate()
                    {
                        Namespace          = namespaceDot + "Resolvers",
                        FormatterNamespace = namespaceDot + "Formatters",
                        ResolverName       = resolverName,
                        RegisterInfos      = genericInfo.Where(x => !x.IsOpenGenericType).Cast <IResolverRegisterInfo>().Concat(enumInfo).Concat(unionInfo).Concat(objectInfo.Where(x => !x.IsOpenGenericType)).ToArray(),
                    };

                    await OutputToDirAsync(output, resolverTemplate.Namespace, resolverTemplate.ResolverName, multioutSymbol, resolverTemplate.TransformText(), cancellationToken);
                }

                if (objectInfo.Length == 0 && enumInfo.Length == 0 && genericInfo.Length == 0 && unionInfo.Length == 0)
                {
                    logger("Generated result is empty, unexpected result?");
                }
            }

            logger("Output Generation Complete:" + sw.Elapsed.ToString());
        }