-
Notifications
You must be signed in to change notification settings - Fork 727
/
BicepCompiler.cs
146 lines (127 loc) · 6.54 KB
/
BicepCompiler.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.Collections.Immutable;
using Bicep.Core.Analyzers.Interfaces;
using Bicep.Core.Configuration;
using Bicep.Core.Diagnostics;
using Bicep.Core.Extensions;
using Bicep.Core.Features;
using Bicep.Core.FileSystem;
using Bicep.Core.Navigation;
using Bicep.Core.Registry;
using Bicep.Core.Semantics;
using Bicep.Core.Semantics.Namespaces;
using Bicep.Core.Syntax;
using Bicep.Core.Utils;
using Bicep.Core.Workspaces;
namespace Bicep.Core;
public class BicepCompiler
{
private readonly IFeatureProviderFactory featureProviderFactory;
private readonly IEnvironment environment;
private readonly INamespaceProvider namespaceProvider;
private readonly IBicepAnalyzer bicepAnalyzer;
private readonly IFileResolver fileResolver;
private readonly IModuleDispatcher moduleDispatcher;
public BicepCompiler(
IFeatureProviderFactory featureProviderFactory,
IEnvironment environment,
INamespaceProvider namespaceProvider,
IConfigurationManager configurationManager,
IBicepAnalyzer bicepAnalyzer,
IFileResolver fileResolver,
IModuleDispatcher moduleDispatcher)
{
this.featureProviderFactory = featureProviderFactory;
this.environment = environment;
this.namespaceProvider = namespaceProvider;
this.ConfigurationManager = configurationManager;
this.bicepAnalyzer = bicepAnalyzer;
this.fileResolver = fileResolver;
this.moduleDispatcher = moduleDispatcher;
}
public IConfigurationManager ConfigurationManager { get; }
public Compilation CreateCompilationWithoutRestore(Uri bicepUri, IReadOnlyWorkspace? workspace = null, bool markAllForRestore = false)
{
workspace ??= new Workspace();
var sourceFileGrouping = SourceFileGroupingBuilder.Build(fileResolver, moduleDispatcher, ConfigurationManager, workspace, bicepUri, featureProviderFactory, markAllForRestore);
return Create(sourceFileGrouping);
}
public async Task<Compilation> CreateCompilation(Uri bicepUri, IReadOnlyWorkspace? workspace = null, bool skipRestore = false, bool forceRestore = false)
{
workspace ??= new Workspace();
var compilation = CreateCompilationWithoutRestore(bicepUri, workspace, markAllForRestore: forceRestore);
var sourceFileGrouping = compilation.SourceFileGrouping;
if (skipRestore)
{
return compilation;
}
// module references in the file may be malformed
// however we still want to surface as many errors as we can for the module refs that are valid
// so we will try to restore modules with valid refs and skip everything else
// (the diagnostics will be collected during compilation)
var artifactsToRestore = sourceFileGrouping.GetArtifactsToRestore(forceRestore);
if (await moduleDispatcher.RestoreArtifacts(ArtifactHelper.GetValidArtifactReferences(artifactsToRestore), forceRestore: forceRestore))
{
// modules had to be restored - recompile
sourceFileGrouping = SourceFileGroupingBuilder.Rebuild(fileResolver, featureProviderFactory, moduleDispatcher, ConfigurationManager, workspace, sourceFileGrouping);
}
return Create(sourceFileGrouping);
}
public async Task<ImmutableDictionary<BicepSourceFile, ImmutableArray<IDiagnostic>>> Restore(Compilation compilation, bool forceRestore)
{
var workspace = new Workspace();
var sourceFileGrouping = compilation.SourceFileGrouping;
var artifactsToRestore = sourceFileGrouping.GetArtifactsToRestore(forceRestore);
if (await moduleDispatcher.RestoreArtifacts(ArtifactHelper.GetValidArtifactReferences(artifactsToRestore), forceRestore))
{
// artifacts had to be restored - recompile
sourceFileGrouping = SourceFileGroupingBuilder.Rebuild(fileResolver, featureProviderFactory, moduleDispatcher, ConfigurationManager, workspace, sourceFileGrouping);
}
return GetModuleRestoreDiagnosticsByBicepFile(sourceFileGrouping, artifactsToRestore.ToImmutableHashSet(), forceRestore);
}
private Compilation Create(SourceFileGrouping sourceFileGrouping)
=> new(
featureProviderFactory,
environment,
namespaceProvider,
sourceFileGrouping,
this.ConfigurationManager,
bicepAnalyzer,
moduleDispatcher,
new AuxiliaryFileCache(fileResolver),
ImmutableDictionary<ISourceFile, ISemanticModel>.Empty);
private static ImmutableDictionary<BicepSourceFile, ImmutableArray<IDiagnostic>> GetModuleRestoreDiagnosticsByBicepFile(SourceFileGrouping sourceFileGrouping, ImmutableHashSet<ArtifactResolutionInfo> originalModulesToRestore, bool forceModulesRestore)
{
static IDiagnostic? DiagnosticForModule(SourceFileGrouping grouping, IArtifactReferenceSyntax moduleDeclaration)
=> grouping.TryGetSourceFile(moduleDeclaration).IsSuccess(out _, out var errorBuilder) ? null : errorBuilder(DiagnosticBuilder.ForPosition(moduleDeclaration.SourceSyntax));
static IEnumerable<(BicepSourceFile, IDiagnostic)> GetDiagnosticsForModulesToRestore(SourceFileGrouping grouping, ImmutableHashSet<ArtifactResolutionInfo> originalArtifactsToRestore)
{
foreach (var artifact in originalArtifactsToRestore)
{
if (artifact.Syntax is { } &&
DiagnosticForModule(grouping, artifact.Syntax) is { } diagnostic)
{
yield return (artifact.Origin, diagnostic);
}
}
}
static IEnumerable<(BicepSourceFile, IDiagnostic)> GetDiagnosticsForAllModules(SourceFileGrouping grouping)
{
foreach (var bicepFile in grouping.SourceFiles.OfType<BicepSourceFile>())
{
foreach (var module in bicepFile.ProgramSyntax.Declarations.OfType<ModuleDeclarationSyntax>())
{
if (DiagnosticForModule(grouping, module) is { } diagnostic)
{
yield return (bicepFile, diagnostic);
}
}
}
}
var diagnosticsByFile = forceModulesRestore ? GetDiagnosticsForAllModules(sourceFileGrouping) : GetDiagnosticsForModulesToRestore(sourceFileGrouping, originalModulesToRestore);
return diagnosticsByFile
.ToLookup(t => t.Item1, t => t.Item2)
.ToImmutableDictionary(g => g.Key, g => g.ToImmutableArray());
}
}