feat(ruby): Implement RubyManifestParser for parsing gem groups and dependencies
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

feat(ruby): Add RubyVendorArtifactCollector to collect vendor artifacts

test(deno): Add golden tests for Deno analyzer with various fixtures

test(deno): Create Deno module and package files for testing

test(deno): Implement Deno lock and import map for dependency management

test(deno): Add FFI and worker scripts for Deno testing

feat(ruby): Set up Ruby workspace with Gemfile and dependencies

feat(ruby): Add expected output for Ruby workspace tests

feat(signals): Introduce CallgraphManifest model for signal processing
This commit is contained in:
master
2025-11-10 09:27:03 +02:00
parent 69c59defdc
commit 56c687253f
87 changed files with 2462 additions and 542 deletions

View File

@@ -0,0 +1,73 @@
using StellaOps.Scanner.Analyzers.Lang.Deno.Fixtures;
internal static class DenoBenchmarkFixtureBuilder
{
public static (string RootPath, string EnvDir) CreateFromTemplate(string templatePath)
{
var root = Path.Combine(Path.GetTempPath(), $"deno-bench-{Guid.NewGuid():N}");
CopyDirectory(templatePath, root);
var envDir = Path.Combine(root, "env-deno");
CreateDenoDir(envDir, "env.ts", includeRegistry: true);
var layerFs = Path.Combine(root, "layers", "sha256-bench", "fs");
Directory.CreateDirectory(layerFs);
CreateDenoDir(Path.Combine(layerFs, ".deno"), "layer.ts");
var bundlesRoot = Path.Combine(root, "bundles");
Directory.CreateDirectory(bundlesRoot);
BundleFixtureBuilder.CreateSampleEszip(bundlesRoot);
BundleFixtureBuilder.CreateSampleCompiledBinary(bundlesRoot);
return (RootPath: root, EnvDir: envDir);
}
private static void CopyDirectory(string source, string destination)
{
foreach (var directory in Directory.EnumerateDirectories(source, "*", SearchOption.AllDirectories))
{
var relative = Path.GetRelativePath(source, directory);
Directory.CreateDirectory(Path.Combine(destination, relative));
}
foreach (var file in Directory.EnumerateFiles(source, "*", SearchOption.AllDirectories))
{
if (file.EndsWith(".actual", StringComparison.OrdinalIgnoreCase))
{
continue;
}
var relative = Path.GetRelativePath(source, file);
var target = Path.Combine(destination, relative);
Directory.CreateDirectory(Path.GetDirectoryName(target)!);
File.Copy(file, target, overwrite: true);
}
}
private static void CreateDenoDir(string root, string fileName, bool includeRegistry = false)
{
var deps = Path.Combine(root, "deps", "https", "benchmark.local");
var gen = Path.Combine(root, "gen");
var npm = Path.Combine(root, "npm");
Directory.CreateDirectory(deps);
Directory.CreateDirectory(gen);
Directory.CreateDirectory(npm);
File.WriteAllText(Path.Combine(deps, fileName), "export const cache = true;");
File.WriteAllText(Path.Combine(gen, $"{Path.GetFileNameWithoutExtension(fileName)}.js"), "console.log(gen);");
File.WriteAllText(Path.Combine(npm, "package.json"), "{}");
if (includeRegistry)
{
CreateNpmRegistryPackage(root);
}
}
private static void CreateNpmRegistryPackage(string denoDirRoot)
{
var registryRoot = Path.Combine(denoDirRoot, "npm", "registry.npmjs.org");
var pkgRoot = Path.Combine(registryRoot, "dayjs", "1.11.12");
Directory.CreateDirectory(pkgRoot);
File.WriteAllText(Path.Combine(pkgRoot, "package.json"), "{\"name\":\"dayjs\",\"version\":\"1.11.12\"}");
}
}

View File

@@ -0,0 +1,46 @@
using StellaOps.Scanner.Analyzers.Lang;
internal static class DenoBenchmarkShared
{
public static string ResolveRepoRoot()
{
var fromEnv = Environment.GetEnvironmentVariable("STELLAOPS_REPO_ROOT");
if (!string.IsNullOrWhiteSpace(fromEnv) && Directory.Exists(fromEnv))
{
return Path.GetFullPath(fromEnv);
}
var directory = Path.GetFullPath(AppContext.BaseDirectory);
while (!string.IsNullOrEmpty(directory))
{
if (Directory.Exists(Path.Combine(directory, ".git")))
{
return directory;
}
var parent = Directory.GetParent(directory)?.FullName;
if (string.IsNullOrEmpty(parent) || string.Equals(parent, directory, StringComparison.Ordinal))
{
break;
}
directory = parent;
}
throw new InvalidOperationException("Unable to locate StellaOps repository root. Set STELLAOPS_REPO_ROOT.");
}
public static string ResolveFixture(string repoRoot, params string[] segments)
{
var path = Path.Combine(new[] { repoRoot }.Concat(segments).ToArray());
if (!Directory.Exists(path))
{
throw new DirectoryNotFoundException($"Fixture path {path} not found.");
}
return path;
}
public static LanguageAnalyzerContext CreateContext(string rootPath)
=> new(rootPath, TimeProvider.System);
}

View File

@@ -0,0 +1,77 @@
using BenchmarkDotNet.Attributes;
using StellaOps.Scanner.Analyzers.Lang;
using StellaOps.Scanner.Analyzers.Lang.Deno;
[MemoryDiagnoser]
public class DenoLanguageAnalyzerBenchmark
{
private LanguageAnalyzerEngine _engine = default!;
private LanguageAnalyzerContext _workspaceContext = default!;
private LanguageAnalyzerContext _containerContext = default!;
private string? _containerEnvDir;
private string? _containerRoot;
[GlobalSetup]
public void Setup()
{
_engine = new LanguageAnalyzerEngine(new ILanguageAnalyzer[] { new DenoLanguageAnalyzer() });
var repoRoot = DenoBenchmarkShared.ResolveRepoRoot();
var workspaceFixture = DenoBenchmarkShared.ResolveFixture(
repoRoot,
"src",
"Scanner",
"__Tests",
"StellaOps.Scanner.Analyzers.Lang.Tests",
"Fixtures",
"lang",
"deno",
"full");
_workspaceContext = DenoBenchmarkShared.CreateContext(workspaceFixture);
var containerFixture = DenoBenchmarkFixtureBuilder.CreateFromTemplate(workspaceFixture);
_containerRoot = containerFixture.RootPath;
_containerEnvDir = containerFixture.EnvDir;
_containerContext = DenoBenchmarkShared.CreateContext(containerFixture.RootPath);
}
[Benchmark(Description = "Full workspace fixture")]
public async Task AnalyzeWorkspaceAsync()
=> await _engine.AnalyzeAsync(_workspaceContext, CancellationToken.None).ConfigureAwait(false);
[Benchmark(Description = "Container-style layout")]
public async Task AnalyzeContainerSurfaceAsync()
{
var previous = Environment.GetEnvironmentVariable("DENO_DIR");
try
{
if (!string.IsNullOrWhiteSpace(_containerEnvDir))
{
Environment.SetEnvironmentVariable("DENO_DIR", _containerEnvDir);
}
await _engine.AnalyzeAsync(_containerContext, CancellationToken.None).ConfigureAwait(false);
}
finally
{
Environment.SetEnvironmentVariable("DENO_DIR", previous);
}
}
[GlobalCleanup]
public void Cleanup()
{
if (!string.IsNullOrEmpty(_containerRoot) && Directory.Exists(_containerRoot))
{
try
{
Directory.Delete(_containerRoot, recursive: true);
}
catch
{
// best-effort cleanup
}
}
}
}

View File

@@ -0,0 +1,3 @@
using BenchmarkDotNet.Running;
BenchmarkRunner.Run<DenoLanguageAnalyzerBenchmark>();

View File

@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>preview</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoWarn>$(NoWarn);NU1603</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.14.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\__Libraries\StellaOps.Scanner.Analyzers.Lang\StellaOps.Scanner.Analyzers.Lang.csproj" />
<ProjectReference Include="..\..\__Libraries\StellaOps.Scanner.Analyzers.Lang.Deno\StellaOps.Scanner.Analyzers.Lang.Deno.csproj" />
<ProjectReference Include="..\..\__Libraries\StellaOps.Scanner.Core\StellaOps.Scanner.Core.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\__Tests\StellaOps.Scanner.Analyzers.Lang.Deno.Tests\TestFixtures\BundleFixtureBuilder.cs" Link="Fixtures\BundleFixtureBuilder.cs" />
</ItemGroup>
</Project>