Files
git.stella-ops.org/src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Lang.Deno/Internal/DenoLockFile.cs
master 69c59defdc
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
feat: Implement Runtime Facts ingestion service and NDJSON reader
- Added RuntimeFactsNdjsonReader for reading NDJSON formatted runtime facts.
- Introduced IRuntimeFactsIngestionService interface and its implementation.
- Enhanced Program.cs to register new services and endpoints for runtime facts.
- Updated CallgraphIngestionService to include CAS URI in stored artifacts.
- Created RuntimeFactsValidationException for validation errors during ingestion.
- Added tests for RuntimeFactsIngestionService and RuntimeFactsNdjsonReader.
- Implemented SignalsSealedModeMonitor for compliance checks in sealed mode.
- Updated project dependencies for testing utilities.
2025-11-10 07:56:15 +02:00

209 lines
7.3 KiB
C#

namespace StellaOps.Scanner.Analyzers.Lang.Deno.Internal;
internal sealed class DenoLockFile
{
private DenoLockFile(
string absolutePath,
string relativePath,
string version,
ImmutableDictionary<string, string> remoteEntries,
ImmutableDictionary<string, string> redirectEntries,
ImmutableDictionary<string, DenoLockNpmPackage> npmPackages,
ImmutableDictionary<string, string> npmSpecifiers)
{
AbsolutePath = Path.GetFullPath(absolutePath);
RelativePath = DenoPathUtilities.NormalizeRelativePath(relativePath);
Version = version;
RemoteEntries = remoteEntries;
Redirects = redirectEntries;
NpmPackages = npmPackages;
NpmSpecifiers = npmSpecifiers;
}
public string AbsolutePath { get; }
public string RelativePath { get; }
public string Version { get; }
public ImmutableDictionary<string, string> RemoteEntries { get; }
public ImmutableDictionary<string, string> Redirects { get; }
public ImmutableDictionary<string, DenoLockNpmPackage> NpmPackages { get; }
public ImmutableDictionary<string, string> NpmSpecifiers { get; }
public static bool TryLoad(string absolutePath, string relativePath, out DenoLockFile? lockFile)
{
lockFile = null;
if (string.IsNullOrWhiteSpace(absolutePath))
{
return false;
}
try
{
using var stream = File.OpenRead(absolutePath);
using var json = JsonDocument.Parse(stream, new JsonDocumentOptions
{
AllowTrailingCommas = true,
CommentHandling = JsonCommentHandling.Skip,
});
var root = json.RootElement;
var version = root.TryGetProperty("version", out var versionElement) && versionElement.ValueKind == JsonValueKind.String
? versionElement.GetString() ?? "unknown"
: "unknown";
var remote = ParseRemoteEntries(root);
var redirects = ParseRedirects(root);
var (npmPackages, npmSpecifiers) = ParseNpmEntries(root);
lockFile = new DenoLockFile(
absolutePath,
relativePath,
version,
remote,
redirects,
npmPackages,
npmSpecifiers);
return true;
}
catch (IOException)
{
return false;
}
catch (JsonException)
{
return false;
}
}
private static ImmutableDictionary<string, string> ParseRemoteEntries(JsonElement root)
{
if (!root.TryGetProperty("remote", out var remoteElement) || remoteElement.ValueKind != JsonValueKind.Object)
{
return ImmutableDictionary<string, string>.Empty;
}
var builder = ImmutableDictionary.CreateBuilder<string, string>(StringComparer.Ordinal);
foreach (var entry in remoteElement.EnumerateObject())
{
if (entry.Value.ValueKind == JsonValueKind.String)
{
builder[entry.Name] = entry.Value.GetString() ?? string.Empty;
}
}
return builder.ToImmutable();
}
private static ImmutableDictionary<string, string> ParseRedirects(JsonElement root)
{
if (!root.TryGetProperty("redirects", out var redirectsElement) || redirectsElement.ValueKind != JsonValueKind.Object)
{
return ImmutableDictionary<string, string>.Empty;
}
var builder = ImmutableDictionary.CreateBuilder<string, string>(StringComparer.Ordinal);
foreach (var entry in redirectsElement.EnumerateObject())
{
if (entry.Value.ValueKind == JsonValueKind.String)
{
builder[entry.Name] = entry.Value.GetString() ?? string.Empty;
}
}
return builder.ToImmutable();
}
private static (ImmutableDictionary<string, DenoLockNpmPackage> Packages, ImmutableDictionary<string, string> Specifiers) ParseNpmEntries(JsonElement root)
{
if (!root.TryGetProperty("npm", out var npmElement) || npmElement.ValueKind != JsonValueKind.Object)
{
return (ImmutableDictionary<string, DenoLockNpmPackage>.Empty, ImmutableDictionary<string, string>.Empty);
}
var packages = ImmutableDictionary.CreateBuilder<string, DenoLockNpmPackage>(StringComparer.OrdinalIgnoreCase);
if (npmElement.TryGetProperty("packages", out var packagesElement) && packagesElement.ValueKind == JsonValueKind.Object)
{
foreach (var packageEntry in packagesElement.EnumerateObject())
{
if (packageEntry.Value.ValueKind != JsonValueKind.Object)
{
continue;
}
var package = DenoLockNpmPackage.Create(packageEntry.Name, packageEntry.Value);
if (package is not null)
{
packages[package.EntryId] = package;
}
}
}
var specifiers = ImmutableDictionary.CreateBuilder<string, string>(StringComparer.Ordinal);
if (npmElement.TryGetProperty("specifiers", out var specifiersElement) && specifiersElement.ValueKind == JsonValueKind.Object)
{
foreach (var specifier in specifiersElement.EnumerateObject())
{
if (specifier.Value.ValueKind == JsonValueKind.String)
{
specifiers[specifier.Name] = specifier.Value.GetString() ?? string.Empty;
}
}
}
return (packages.ToImmutable(), specifiers.ToImmutable());
}
}
internal sealed class DenoLockNpmPackage
{
private DenoLockNpmPackage(
string entryId,
string integrity,
ImmutableDictionary<string, string> dependencies)
{
EntryId = entryId;
Integrity = integrity;
Dependencies = dependencies;
}
public string EntryId { get; }
public string Integrity { get; }
public ImmutableDictionary<string, string> Dependencies { get; }
public static DenoLockNpmPackage? Create(string entryId, JsonElement element)
{
if (string.IsNullOrWhiteSpace(entryId) || element.ValueKind != JsonValueKind.Object)
{
return null;
}
var integrity = element.TryGetProperty("integrity", out var integrityElement) && integrityElement.ValueKind == JsonValueKind.String
? integrityElement.GetString() ?? string.Empty
: string.Empty;
var dependencies = ImmutableDictionary<string, string>.Empty;
if (element.TryGetProperty("dependencies", out var dependenciesElement) && dependenciesElement.ValueKind == JsonValueKind.Object)
{
var builder = ImmutableDictionary.CreateBuilder<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (var dependency in dependenciesElement.EnumerateObject())
{
if (dependency.Value.ValueKind == JsonValueKind.String)
{
builder[dependency.Name] = dependency.Value.GetString() ?? string.Empty;
}
}
dependencies = builder.ToImmutable();
}
return new DenoLockNpmPackage(entryId, integrity, dependencies);
}
}