using System.Diagnostics; using System.Security.Cryptography; using System.Text.Json; using AngleSharp.Html.Parser; using Jint; using XFESystem.Browser; var root = Path.GetFullPath(args.Length > 0 ? args[0] : "."); var assetRoot = Path.Combine(root, "assets/Browser/Monaco/0.52.2"); var run = Path.Combine(root, "build/BrowserProbe", "Run-" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()); Directory.CreateDirectory(run); var loaderPath = Path.Combine(assetRoot, "min/vs/loader.js"); var mainPath = Path.Combine(assetRoot, "min/vs/editor/editor.main.js"); var loader = File.ReadAllText(loaderPath); var main = File.ReadAllText(mainPath); var stages = new List(); JavaScriptRuntime Create(bool expanded = false) { var limits = expanded ? new BrowserLimits { MaximumScriptCharacters = 1_048_576, MaximumScriptMemoryBytes = 268_435_456, MaximumStatements = 10_000_000, MaximumRecursionDepth = 256, ScriptTimeout = TimeSpan.FromSeconds(30) } : new BrowserLimits(); var runtime = new JavaScriptRuntime(limits); var document = new HtmlParser().ParseDocument("
"); _ = new DomBridge(runtime, document, new Uri("http://xfe.test/Monaco/"), limits); return runtime; } bool Step(JavaScriptRuntime runtime, string name, string source, bool bypassCharacterLimit = false) { var timer = Stopwatch.StartNew(); bool success; string error; try { if (bypassCharacterLimit) { runtime.Engine.Execute(source); success = true; error = ""; } else { var result = runtime.Evaluate(source); success = result.Success; error = result.Error; } } catch (Exception ex) { success = false; error = ex.ToString(); } stages.Add(new { Name = name, SourceCharacters = source.Length, BypassCharacterLimit = bypassCharacterLimit, Success = success, Error = error, ElapsedMilliseconds = timer.Elapsed.TotalMilliseconds }); Console.WriteLine(JsonSerializer.Serialize(new { Name = name, Success = success, Error = error.Length > 1500 ? error[..1500] : error })); return success; } var current = Create(); Step(current, "ProductionProfile.RealLoader", loader); Step(current, "ProductionProfile.RealEditorBundle", main); var expanded = Create(true); Step(expanded, "ExpandedProbe.RealLoader", loader); Step(expanded, "ExpandedProbe.RealEditorBundle", main, true); Step(expanded, "ExpandedProbe.RequireEditor", "require(['vs/editor/editor.main'],function(){globalThis.__xfeLoaded=true;},function(e){throw e;});"); Step(expanded, "ExpandedProbe.CreateRealEditor", "globalThis.__xfeEditor=monaco.editor.create(document.getElementById('container'),{value:'const answer = 42;',language:'javascript',automaticLayout:false});"); var withNavigator = Create(true); Step(withNavigator, "NavigatorProbe.Platform", "globalThis.navigator={userAgent:'XFESystem/MonacoProbe',platform:'XFESystem',language:'en-US',languages:['en-US'],hardwareConcurrency:1,onLine:false};globalThis.location={href:'http://xfe.test/Monaco/',protocol:'http:',hostname:'xfe.test',host:'xfe.test',origin:'http://xfe.test',pathname:'/Monaco/',search:'',hash:''};"); Step(withNavigator, "NavigatorProbe.RealLoader", loader); Step(withNavigator, "NavigatorProbe.RealEditorBundle", main, true); var withoutCss = Create(true); Step(withoutCss, "NoCssProbe.Platform", "globalThis.navigator={userAgent:'XFESystem/MonacoProbe',platform:'XFESystem',language:'en-US',languages:['en-US'],hardwareConcurrency:1,onLine:false};globalThis.location={href:'http://xfe.test/Monaco/',protocol:'http:',hostname:'xfe.test',host:'xfe.test',origin:'http://xfe.test',pathname:'/Monaco/',search:'',hash:''};"); Step(withoutCss, "NoCssProbe.RealLoader", loader); Step(withoutCss, "NoCssProbe.OfficialCssPluginDisabledForDiagnosis", "require.config({'vs/css':{disabled:true}});"); Step(withoutCss, "NoCssProbe.RealEditorBundle", main, true); var platform = "globalThis.navigator={userAgent:'XFESystem/MonacoProbe',platform:'XFESystem',language:'en-US',languages:['en-US'],hardwareConcurrency:1,onLine:false};globalThis.location={href:'http://xfe.test/Monaco/',protocol:'http:',hostname:'xfe.test',host:'xfe.test',origin:'http://xfe.test',pathname:'/Monaco/',search:'',hash:''};document.queryCommandSupported=function(command){return false;};"; var tasks = File.ReadAllText(Path.Combine(root, "Tools/BrowserCompatibility/ProbeTasks.js")); var events = File.ReadAllText(Path.Combine(root, "Tools/BrowserCompatibility/ProbeWindowEvents.js")); var tokens = File.ReadAllText(Path.Combine(root, "Tools/BrowserCompatibility/ProbeDomTokens.js")); foreach (var diagnostic in new[] { (Name:"TaskProbe", Script:tasks), (Name:"WindowEventProbe", Script:tasks + "\n" + events), (Name:"DomTokenProbe", Script:tasks + "\n" + events + "\n" + tokens) }) { var candidate = Create(true); Step(candidate, diagnostic.Name + ".Platform", platform + diagnostic.Script); Step(candidate, diagnostic.Name + ".RealLoader", loader); Step(candidate, diagnostic.Name + ".OfficialCssPluginDisabledForDiagnosis", "require.config({'vs/css':{disabled:true}});"); if (Step(candidate, diagnostic.Name + ".RealEditorBundle", main, true)) { Step(candidate, diagnostic.Name + ".RequireRealEditor", "require(['vs/editor/editor.main'],function(){globalThis.__xfeLoaded=true;},function(e){throw e;});__xfeCheckpoint();if(!globalThis.__xfeLoaded)throw new Error('Real editor.main has not completed');"); Step(candidate, diagnostic.Name + ".CreateRealEditor", "globalThis.__xfeEditor=monaco.editor.create(document.getElementById('container'),{value:'const answer = 42;',language:'javascript',automaticLayout:false});", true); } } var resultPath = Path.Combine(run, "Result.json"); var result = new { Kind = "RealMonacoJintCompatibilityProbe", MonacoVersion = "0.52.2", JintVersion = "4.11.0", ProductionBrowserModified = false, ProbeOnly = true, NativeGuestTested = false, HostBrowserUsed = false, FakeMonacoObjects = false, ExpandedBudgetIsProductionSupport = false, LoaderSha256 = Convert.ToHexStringLower(SHA256.HashData(File.ReadAllBytes(loaderPath))), EditorBundleSha256 = Convert.ToHexStringLower(SHA256.HashData(File.ReadAllBytes(mainPath))), Baseline = Directory.GetFiles(Path.Combine(root, "build/BrowserProbe/InitialBaseline"), "*.cs") .Select(p => new { Name = Path.GetFileName(p), Sha256 = Convert.ToHexStringLower(SHA256.HashData(File.ReadAllBytes(p))) }).ToArray(), Stages = stages }; File.WriteAllText(resultPath, JsonSerializer.Serialize(result, new JsonSerializerOptions { WriteIndented = true })); Console.WriteLine(resultPath);