Files
sbox-public/engine/Sandbox.Compiling/Compiler/Compiler.Razor.cs
s&box team 71f266059a Open source release
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
2025-11-24 09:05:18 +00:00

84 lines
2.8 KiB
C#

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Collections.Concurrent;
namespace Sandbox;
partial class Compiler
{
/// <summary>
/// Process Razor files from the code archive and generate C# syntax trees
/// </summary>
private List<SyntaxTree> ProcessRazorFiles( CodeArchive archive, CompilerOutput output )
{
var razorFiles = archive.AdditionalFiles
.Where( x => x.LocalPath.EndsWith( ".razor", System.StringComparison.OrdinalIgnoreCase ) )
.ToList();
if ( razorFiles.Count == 0 )
return [];
var trees = new ConcurrentBag<SyntaxTree>();
var diagnostics = new ConcurrentBag<Diagnostic>();
Parallel.ForEach( razorFiles, file =>
{
var hash = file.LocalPath.FastHash();
string filenameOnly = System.IO.Path.GetFileName( file.LocalPath );
if ( file.Text is null )
{
var desc = new DiagnosticDescriptor( "SB6000", "Razor Error", $"Error reading {file.LocalPath}", "razor", DiagnosticSeverity.Error, true );
diagnostics.Add( Diagnostic.Create( desc, null ) );
return;
}
try
{
// Use the existing RazorProcessor to generate C# code from the Razor file
// Pass the root namespace so Razor can auto-generate @namespace directives from folder structure
var generatedCode = Sandbox.Razor.RazorProcessor.GenerateFromSource( file.Text, file.LocalPath, archive.Configuration.RootNamespace, !archive.Version_UsesOldRazorNamespaces );
// Create the generated file path using the same naming convention
string filePath = $"_gen_{filenameOnly}_{hash:x}.cs";
// Parse the generated C# code into a syntax tree
var tree = CSharpSyntaxTree.ParseText( generatedCode, path: filePath, encoding: System.Text.Encoding.UTF8 );
// Check for duplicates
if ( trees.Any( x => x.FilePath == filePath ) )
{
var desc = new DiagnosticDescriptor( "SB6001", "Razor Error", $"Duplicate Razor Component: {file.LocalPath}", "razor", DiagnosticSeverity.Error, true );
diagnostics.Add( Diagnostic.Create( desc, null ) );
return;
}
trees.Add( tree );
// Map the generated file path to the original .razor file for debugging support
lock ( archive.FileMap )
{
archive.FileMap[filePath] = file.LocalPath;
// If we had a relative version of this path stored, then use that instead
if ( archive.FileMap.TryGetValue( file.LocalPath, out var relativePath ) )
archive.FileMap[filePath] = relativePath;
}
}
catch ( System.Exception ex )
{
var desc = new DiagnosticDescriptor( "SB6002", "Razor Error", $"Error processing {file.LocalPath}: {ex.Message}", "razor", DiagnosticSeverity.Error, true );
diagnostics.Add( Diagnostic.Create( desc, null ) );
}
} );
// Add any diagnostics to the output
if ( diagnostics.Any() )
{
output.Diagnostics.AddRange( diagnostics );
}
return trees.OrderBy( x => x.FilePath ).ToList();
}
}