public static ProgramSyntax DecompileTemplate(Workspace workspace, IFileResolver fileResolver, Uri fileUri, string content)
        {
            var instance = new TemplateConverter(workspace, fileResolver, fileUri, JObject.Parse(content, new JsonLoadSettings
            {
                CommentHandling  = CommentHandling.Ignore,
                LineInfoHandling = LineInfoHandling.Load,
            }));

            return(instance.Parse());
        }
Example #2
0
        public static (Uri entrypointUri, ImmutableDictionary <Uri, string> filesToSave) DecompileFileWithModules(IResourceTypeProvider resourceTypeProvider, IFileResolver fileResolver, Uri jsonUri)
        {
            var decompileQueue = new Queue <Uri>();

            var entryUri  = ChangeExtension(jsonUri, "bicep");
            var workspace = new Workspace();

            decompileQueue.Enqueue(entryUri);

            while (decompileQueue.Any())
            {
                var bicepUri = decompileQueue.Dequeue();
                if (!bicepUri.AbsolutePath.EndsWith(".bicep", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                var currentJsonUri = ChangeExtension(bicepUri, "json");

                if (workspace.TryGetSyntaxTree(bicepUri, out _))
                {
                    continue;
                }

                if (!fileResolver.TryRead(currentJsonUri, out var jsonInput, out _))
                {
                    throw new InvalidOperationException($"Failed to read {currentJsonUri}");
                }

                var program    = TemplateConverter.DecompileTemplate(workspace, fileResolver, currentJsonUri, jsonInput);
                var syntaxTree = new SyntaxTree(bicepUri, ImmutableArray <int> .Empty, program);
                workspace.UpsertSyntaxTrees(syntaxTree.AsEnumerable());

                foreach (var module in program.Children.OfType <ModuleDeclarationSyntax>())
                {
                    var moduleRelativePath = SyntaxHelper.TryGetModulePath(module, out _);
                    if (moduleRelativePath == null ||
                        !SyntaxTreeGroupingBuilder.ValidateModulePath(moduleRelativePath, out _) ||
                        !Uri.TryCreate(bicepUri, moduleRelativePath, out var moduleUri))
                    {
                        // Do our best, but keep going if we fail to resolve a module file
                        continue;
                    }

                    if (!workspace.TryGetSyntaxTree(moduleUri, out _))
                    {
                        decompileQueue.Enqueue(moduleUri);
                    }
                }
            }

            RewriteSyntax(resourceTypeProvider, workspace, entryUri, semanticModel => new ParentChildResourceNameRewriter(semanticModel));
            RewriteSyntax(resourceTypeProvider, workspace, entryUri, semanticModel => new DependsOnRemovalRewriter(semanticModel));
            RewriteSyntax(resourceTypeProvider, workspace, entryUri, semanticModel => new ForExpressionSimplifierRewriter(semanticModel));
            for (var i = 0; i < 5; i++)
            {
                // This is a little weird. If there are casing issues nested inside casing issues (e.g. in an object), then the inner casing issue will have no type information
                // available, as the compilation will not have associated a type with it (since there was no match on the outer object). So we need to correct the outer issue first,
                // and then move to the inner one. We need to recompute the entire compilation to do this. It feels simpler to just do this in passes over the file, rather than on demand.
                if (!RewriteSyntax(resourceTypeProvider, workspace, entryUri, semanticModel => new TypeCasingFixerRewriter(semanticModel)))
                {
                    break;
                }
            }

            return(entryUri, PrintFiles(workspace));
        }
Example #3
0
        public static ProgramSyntax DecompileTemplate(IFileResolver fileResolver, Uri fileUri, string content)
        {
            var instance = new TemplateConverter(fileResolver, fileUri, content);

            return(instance.Parse());
        }
Example #4
0
        public static (Uri entrypointUri, ImmutableDictionary <Uri, string> filesToSave) DecompileFileWithModules(IFileResolver fileResolver, Uri jsonUri)
        {
            var decompiled     = new Dictionary <Uri, ProgramSyntax>();
            var decompileQueue = new Queue <Uri>();

            var entryUri = ChangeExtension(jsonUri, "bicep");

            decompileQueue.Enqueue(entryUri);

            while (decompileQueue.Any())
            {
                var bicepUri = decompileQueue.Dequeue();
                if (!bicepUri.AbsolutePath.EndsWith(".bicep", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                var currentJsonUri = ChangeExtension(bicepUri, "json");

                if (decompiled.ContainsKey(bicepUri))
                {
                    continue;
                }

                if (!fileResolver.TryRead(currentJsonUri, out var jsonInput, out _))
                {
                    throw new InvalidOperationException($"Failed to read {currentJsonUri}");
                }

                var program = TemplateConverter.DecompileTemplate(fileResolver, currentJsonUri, jsonInput);
                decompiled[bicepUri] = program;

                foreach (var module in program.Children.OfType <ModuleDeclarationSyntax>())
                {
                    var moduleRelativePath = SyntaxHelper.TryGetModulePath(module, out _);

                    if (moduleRelativePath == null || !Uri.TryCreate(bicepUri, moduleRelativePath, out var moduleUri))
                    {
                        throw new ArgumentException($"Failed to resolve {moduleRelativePath} relative to {bicepUri}");
                    }

                    if (!decompiled.ContainsKey(moduleUri))
                    {
                        decompileQueue.Enqueue(moduleUri);
                    }
                }
            }

            var filesToSave = new Dictionary <Uri, string>();

            foreach (var(fileUri, program) in decompiled)
            {
                var bicepOutput = PrettyPrinter.PrintProgram(program, new PrettyPrintOptions(NewlineOption.Auto, IndentKindOption.Space, 2, false));

                if (bicepOutput == null)
                {
                    throw new ArgumentException($"Failed to pring bicep file {fileUri}");
                }

                filesToSave[fileUri] = bicepOutput;
            }

            return(entryUri, filesToSave.ToImmutableDictionary());
        }
Example #5
0
        public (Uri entrypointUri, ImmutableDictionary <Uri, string> filesToSave) DecompileFileWithModules(Uri entryJsonUri, Uri entryBicepUri)
        {
            var workspace      = new Workspace();
            var decompileQueue = new Queue <(Uri, Uri)>();

            decompileQueue.Enqueue((entryJsonUri, entryBicepUri));

            while (decompileQueue.Count > 0)
            {
                var(jsonUri, bicepUri) = decompileQueue.Dequeue();

                if (PathHelper.HasBicepExtension(jsonUri))
                {
                    throw new InvalidOperationException($"Cannot decompile the file with .bicep extension: {jsonUri}.");
                }

                if (workspace.TryGetSourceFile(bicepUri, out _))
                {
                    continue;
                }

                if (!fileResolver.TryRead(jsonUri, out var jsonInput, out _))
                {
                    throw new InvalidOperationException($"Failed to read {jsonUri}");
                }

                var(program, jsonTemplateUrisByModule) = TemplateConverter.DecompileTemplate(workspace, fileResolver, bicepUri, jsonInput);
                var bicepFile = SourceFileFactory.CreateBicepFile(bicepUri, program.ToText());
                workspace.UpsertSourceFile(bicepFile);

                foreach (var module in program.Children.OfType <ModuleDeclarationSyntax>())
                {
                    var moduleRelativePath = SyntaxHelper.TryGetModulePath(module, out _);
                    if (moduleRelativePath == null ||
                        !LocalModuleReference.Validate(moduleRelativePath, out _) ||
                        !Uri.TryCreate(bicepUri, moduleRelativePath, out var moduleUri))
                    {
                        // Do our best, but keep going if we fail to resolve a module file
                        continue;
                    }

                    if (!workspace.TryGetSourceFile(moduleUri, out _) && jsonTemplateUrisByModule.TryGetValue(module, out var linkedTemplateUri))
                    {
                        decompileQueue.Enqueue((linkedTemplateUri, moduleUri));
                    }
                }
            }

            RewriteSyntax(workspace, entryBicepUri, semanticModel => new ParentChildResourceNameRewriter(semanticModel));
            RewriteSyntax(workspace, entryBicepUri, semanticModel => new DependsOnRemovalRewriter(semanticModel));
            RewriteSyntax(workspace, entryBicepUri, semanticModel => new ForExpressionSimplifierRewriter(semanticModel));
            for (var i = 0; i < 5; i++)
            {
                // This is a little weird. If there are casing issues nested inside casing issues (e.g. in an object), then the inner casing issue will have no type information
                // available, as the compilation will not have associated a type with it (since there was no match on the outer object). So we need to correct the outer issue first,
                // and then move to the inner one. We need to recompute the entire compilation to do this. It feels simpler to just do this in passes over the file, rather than on demand.
                if (!RewriteSyntax(workspace, entryBicepUri, semanticModel => new TypeCasingFixerRewriter(semanticModel)))
                {
                    break;
                }
            }

            return(entryBicepUri, PrintFiles(workspace));
        }