using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Text.Json.Serialization;
namespace Sandbox;
partial class Compiler
{
public enum ReleaseMode
{
Debug,
Release
}
public struct Configuration
{
public Configuration()
{
Clean();
}
public string RootNamespace { get; set; }
[Title( "Symbols" ), Description( "A list of pre-processor symbols to define when compiling, separated with semi-colons." )]
public string DefineConstants { get; set; } = "SANDBOX";
public string NoWarn { get; set; } = "1701;1702;1591;";
public string WarningsAsErrors { get; set; } = "";
public bool TreatWarningsAsErrors { get; set; }
public bool Nullables { get; set; }
///
/// If true, we will be using the whitelist system. If false then this package won't
/// be "sandboxed", so won't be able to be published on the platform.
///
[JsonIgnore]
public bool Whitelist { get; set; } = true;
///
/// If true, we'll compile with /unsafe. This means that the package won't be able to
/// be published on the platform.
///
[JsonIgnore]
public bool Unsafe { get; set; } = false;
///
/// The current release mode. This only matters during local development.
/// Published games are always built in release mode, where optimizations are enabled and debugging is limited (breakpoints, sequence points, and locals may be unavailable).
///
public ReleaseMode ReleaseMode { get; set; }
///
/// References to non-package assemblies, by assembly name.
///
public List AssemblyReferences { get; set; }
///
/// Maps file patterns to preprocessor directives they should be wrapped in
///
public Dictionary ReplacementDirectives { get; set; }
///
/// Strips disabled text trivia from the syntax tree. This is stuff like `#if false` blocks that are not compiled.
///
internal bool StripDisabledTextTrivia { get; set; } = false;
///
/// Folders to ignore when walking the tree
///
public HashSet IgnoreFolders { get; set; } = new HashSet();
static bool IsPermittedAssemblyReference( string assemblyName )
{
return assemblyName.StartsWith( "Sandbox.", StringComparison.OrdinalIgnoreCase )
|| assemblyName.StartsWith( "Facepunch.", StringComparison.OrdinalIgnoreCase )
|| assemblyName == "Microsoft.AspNetCore.Components";
}
///
/// Each unique element of
///
public IReadOnlySet DistinctAssemblyReferences => new HashSet( AssemblyReferences.Where( IsPermittedAssemblyReference ), StringComparer.OrdinalIgnoreCase );
public void Clean()
{
if ( string.IsNullOrWhiteSpace( RootNamespace ) )
RootNamespace = "Sandbox";
AssemblyReferences ??= new();
IgnoreFolders ??= new();
ReplacementDirectives ??= new()
{
{ ".Server.cs", "SERVER" } // Include .Server.cs replacements by default
};
}
internal Dictionary GetReportDiagnostics()
{
var diags = NoWarn.Split( ";", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries );
var diagnostics = diags.ToDictionary( x => $"CS{x}", y => ReportDiagnostic.Suppress );
// alex: I had support for the "nullable" shorthand in here but it doesn't appear to work with CSharpCompilationOptions
// (see https://github.com/dotnet/roslyn/issues/52414) so I've removed it for now.
var warns = WarningsAsErrors.Split( ";", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries );
foreach ( var warn in warns )
diagnostics.Add( $"CS{warn}", ReportDiagnostic.Error );
return diagnostics;
}
///
/// Fetches the preprocessor symbols, which might've changed based on criteria
///
///
public HashSet GetPreprocessorSymbols()
{
var symbols = DefineConstants.Split( ";", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries )
.ToHashSet();
if ( ReleaseMode == ReleaseMode.Debug )
{
symbols.Add( "DEBUG" );
}
else
{
symbols.Remove( "DEBUG" );
}
return symbols;
}
///
/// Returns the CSharpParseOptions for this configuration, which includes the preprocessor symbols defined in .
///
///
public CSharpParseOptions GetParseOptions()
{
return CSharpParseOptions.Default
.WithLanguageVersion( LanguageVersion.CSharp14 )
.WithPreprocessorSymbols( GetPreprocessorSymbols() );
}
}
}