Пример #1
0
        private static bool RewriteSyntax(IResourceTypeProvider resourceTypeProvider, Workspace workspace, Uri entryUri, Func <SemanticModel, SyntaxRewriteVisitor> rewriteVisitorBuilder)
        {
            var hasChanges         = false;
            var syntaxTreeGrouping = SyntaxTreeGroupingBuilder.Build(new FileResolver(), workspace, entryUri);
            var compilation        = new Compilation(resourceTypeProvider, syntaxTreeGrouping);

            foreach (var(fileUri, syntaxTree) in workspace.GetActiveSyntaxTrees())
            {
                var entryFile  = syntaxTreeGrouping.EntryPoint;
                var entryModel = compilation.GetEntrypointSemanticModel();

                var newProgramSyntax = rewriteVisitorBuilder(compilation.GetSemanticModel(syntaxTree)).Rewrite(syntaxTree.ProgramSyntax);

                if (!object.ReferenceEquals(syntaxTree.ProgramSyntax, newProgramSyntax))
                {
                    hasChanges = true;
                    var newSyntaxTree = new SyntaxTree(fileUri, ImmutableArray <int> .Empty, newProgramSyntax);
                    workspace.UpsertSyntaxTrees(newSyntaxTree.AsEnumerable());

                    syntaxTreeGrouping = SyntaxTreeGroupingBuilder.Build(new FileResolver(), workspace, entryUri);
                    compilation        = new Compilation(resourceTypeProvider, syntaxTreeGrouping);
                }
            }

            return(hasChanges);
        }
Пример #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));
        }