forked from Azure/bicep
-
Notifications
You must be signed in to change notification settings - Fork 0
/
TemplateEmitter.cs
142 lines (121 loc) · 5.27 KB
/
TemplateEmitter.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
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.Collections.Immutable;
using System.Text;
using Bicep.Core.Diagnostics;
using Bicep.Core.Emit.Options;
using Bicep.Core.Semantics;
using Bicep.Core.Syntax;
using Newtonsoft.Json;
namespace Bicep.Core.Emit;
public class TemplateEmitter
{
private readonly ISemanticModel model;
public TemplateEmitter(SemanticModel model)
{
this.model = model;
}
/// <summary>
/// The JSON spec requires UTF8 without a BOM, so we use this encoding to write JSON files.
/// </summary>
public static Encoding UTF8EncodingWithoutBom { get; } = new UTF8Encoding(false);
/// <summary>
/// Emits a template to the specified stream if there are no errors. No writes are made to the stream if there are compilation errors.
/// </summary>
/// <param name="stream">The stream to write the template</param>
/// <param name="existingContent">Existing content of the parameters file</param>
/// <param name="outputFormat">Output file format (json or bicepparam)</param>
/// <param name="includeParams">Include parameters (requiredonly or all)</param>
public EmitResult EmitTemplateGeneratedParameterFile(Stream stream, string existingContent, OutputFormatOption outputFormat, IncludeParamsOption includeParams)
{
using var sw = new StreamWriter(stream, UTF8EncodingWithoutBom, 4096, leaveOpen: true);
return EmitTemplateGeneratedParameterFile(sw, existingContent, outputFormat, includeParams);
}
/// <summary>
/// Emits a template to the specified json writer if there are no errors. No writes are made to the writer if there are compilation errors.
/// </summary>
/// <param name="textWriter">The text writer to write the template</param>
/// <param name="existingContent">Existing content of the parameters file</param>
/// <param name="outputFormat">Output file format (json or bicepparam)</param>
/// <param name="includeParams">Include parameters (requiredonly or all)</param>
public EmitResult EmitTemplateGeneratedParameterFile(TextWriter textWriter, string existingContent, OutputFormatOption outputFormat, IncludeParamsOption includeParams) => this.EmitOrFail(() =>
{
if (model is not SemanticModel bicepSemanticModel)
{
throw new InvalidOperationException($"This action is only supported for Bicep files");
}
switch (outputFormat)
{
case OutputFormatOption.BicepParam:
{
var bicepParamEmitter = new PlaceholderParametersBicepParamWriter(bicepSemanticModel, includeParams);
bicepParamEmitter.Write(textWriter, existingContent);
break;
}
case OutputFormatOption.Json:
default:
{
using var writer = new JsonTextWriter(textWriter)
{
// don't close the textWriter when writer is disposed
CloseOutput = false,
Formatting = Formatting.Indented
};
var jsonEmitter = new PlaceholderParametersJsonWriter(bicepSemanticModel, includeParams);
jsonEmitter.Write(writer, existingContent);
writer.Flush();
break;
}
}
return null;
});
/// <summary>
/// Emits a template to the specified stream if there are no errors. No writes are made to the stream if there are compilation errors.
/// </summary>
/// <param name="stream">The stream to write the template</param>
public EmitResult Emit(Stream stream)
{
using var sw = new StreamWriter(stream, UTF8EncodingWithoutBom, 4096, leaveOpen: true)
{
NewLine = "\n",
};
return Emit(sw);
}
/// <summary>
/// Emits a template to the specified text writer if there are no errors. No writes are made to the writer if there are compilation errors.
/// </summary>
/// <param name="textWriter">The text writer to write the template</param>
public EmitResult Emit(TextWriter textWriter) => EmitOrFail(() =>
{
var sourceFileToTrack = model switch
{
SemanticModel bicepModel when bicepModel.Features.SourceMappingEnabled => bicepModel.SourceFile,
_ => null,
};
using var writer = new SourceAwareJsonTextWriter(textWriter, sourceFileToTrack)
{
// don't close the textWriter when writer is disposed
CloseOutput = false,
Formatting = Formatting.Indented
};
var emitter = TemplateWriterFactory.CreateTemplateWriter(this.model);
emitter.Write(writer);
writer.Flush();
return writer.SourceMap;
});
private EmitResult EmitOrFail(Func<SourceMap?> write)
{
// collect all the diagnostics
var diagnostics = model switch
{
SemanticModel x => x.GetAllDiagnostics(),
_ => [],
};
if (diagnostics.Any(d => d.IsError()))
{
return new EmitResult(EmitStatus.Failed, diagnostics);
}
var sourceMap = write();
return new EmitResult(EmitStatus.Succeeded, diagnostics, sourceMap);
}
}