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)); }
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()); }