Skip to main content
Glama
compliance-report.mapper.ts6.55 kB
/** * @fileoverview ComplianceReport mapper * * Maps between DeepSource API models and domain ComplianceReport aggregates. */ import { ComplianceReport } from '../../domain/aggregates/compliance-report/compliance-report.aggregate.js'; import { ComplianceReport as ApiComplianceReport } from '../../deepsource.js'; import { CreateComplianceReportParams, ComplianceCategory, ComplianceReportStatus, } from '../../domain/aggregates/compliance-report/compliance-report.types.js'; import { asProjectKey, asGraphQLNodeId } from '../../types/branded.js'; import { IssueCount } from '../../domain/value-objects/issue-count.js'; import { ReportType } from '../../types/report-types.js'; /** * Maps the highest severity from occurrence distribution * * @param occurrence - The severity distribution * @returns The highest severity present */ function mapHighestSeverity( occurrence: ApiComplianceReport['securityIssueStats'][0]['occurrence'] ): 'CRITICAL' | 'MAJOR' | 'MINOR' | 'INFO' { if (occurrence.critical > 0) return 'CRITICAL'; if (occurrence.major > 0) return 'MAJOR'; if (occurrence.minor > 0) return 'MINOR'; return 'INFO'; } /** * Maps the API report status to domain status * * @param apiStatus - The API status * @returns The domain report status */ function mapReportStatus(apiStatus?: string): ComplianceReportStatus { const statusMap: Record<string, ComplianceReportStatus> = { READY: 'READY', COMPLETED: 'READY', GENERATING: 'GENERATING', PENDING: 'GENERATING', ERROR: 'ERROR', FAILED: 'ERROR', PASSING: 'PASSING', FAILING: 'FAILING', NOOP: 'NOT_APPLICABLE', }; return statusMap[apiStatus || ''] || 'PENDING'; } /** * Maps a DeepSource API compliance report to domain ComplianceReport aggregate * * @param apiReport - The API compliance report model * @param projectKey - The project key * @param repositoryId - The repository GraphQL ID * @returns The domain ComplianceReport aggregate */ export function mapComplianceReportToDomain( apiReport: ApiComplianceReport, projectKey: string, repositoryId: string ): ComplianceReport { const categories: ComplianceCategory[] = apiReport.securityIssueStats.map((stat) => { // API provides total directly, but we can also calculate it for verification const totalIssues = stat.occurrence.total || stat.occurrence.critical + stat.occurrence.major + stat.occurrence.minor; // Simple approach: treat all detected issues as non-compliant // In a real implementation, this would depend on business rules about what constitutes compliance return { name: stat.title, description: `Security category: ${stat.key}`, compliant: IssueCount.create(0), // API doesn't provide compliant count directly nonCompliant: IssueCount.create(totalIssues), issueCount: IssueCount.create(totalIssues), severity: mapHighestSeverity(stat.occurrence), }; }); const params: CreateComplianceReportParams = { projectKey: asProjectKey(projectKey), repositoryId: asGraphQLNodeId(repositoryId), reportType: apiReport.key, status: mapReportStatus(apiReport.status), categories, }; return ComplianceReport.create(params); } /** * Maps a domain ComplianceReport aggregate to persistence format * * @param report - The domain ComplianceReport aggregate * @returns The persistence model */ export function mapComplianceReportToPersistence(report: ComplianceReport): { id: string; projectKey: string; repositoryId: string; reportType: ReportType; status: ComplianceReportStatus; categories: ComplianceCategory[]; generatedAt: Date; lastUpdated: Date; } { const persistence = report.toPersistence(); return { ...persistence, projectKey: persistence.projectKey as string, repositoryId: persistence.repositoryId as string, }; } /** * Creates a category from API security issue stat * * @param stat - The API security issue statistic * @param reportType - The report type for context * @returns A compliance category */ export function createCategoryFromStat( stat: { key: string; title: string; occurrence: { critical: number; major: number; minor: number; total: number }; }, reportType: ReportType ): ComplianceCategory { // API provides total directly, but we can also calculate it for verification const totalIssues = stat.occurrence.total || stat.occurrence.critical + stat.occurrence.major + stat.occurrence.minor; return { name: stat.title, description: `${reportType} category: ${stat.key}`, compliant: IssueCount.create(0), // We don't have compliant count from API nonCompliant: IssueCount.create(totalIssues), issueCount: IssueCount.create(totalIssues), severity: mapHighestSeverity(stat.occurrence), }; } /** * Estimates compliance score based on issue counts * This is a simplified calculation since the API doesn't provide the exact score * * @param categories - The compliance categories * @returns Estimated compliance score (0-100) */ export function estimateComplianceScore(categories: ComplianceCategory[]): number { if (categories.length === 0) return 100; const totalIssues = categories.reduce((sum, cat) => sum + cat.issueCount.count, 0); const criticalIssues = categories.filter((cat) => cat.severity === 'CRITICAL').length; const majorIssues = categories.filter((cat) => cat.severity === 'MAJOR').length; // Simple scoring: penalize critical and major issues more heavily const penalty = criticalIssues * 20 + majorIssues * 10 + totalIssues * 2; return Math.max(0, Math.min(100, 100 - penalty)); } /** * Maps multiple API compliance reports to domain aggregates * * @param apiReports - Array of API compliance reports * @param projectKey - The project key * @param repositoryId - The repository GraphQL ID * @returns Array of domain ComplianceReport aggregates */ export function mapComplianceReportsFromList( apiReports: ApiComplianceReport[], projectKey: string, repositoryId: string ): ComplianceReport[] { return apiReports.map((report) => mapComplianceReportToDomain(report, projectKey, repositoryId)); } // For backward compatibility, export a namespace with the old static methods export const ComplianceReportMapper = { toDomain: mapComplianceReportToDomain, mapStatus: mapReportStatus, mapHighestSeverity, toPersistence: mapComplianceReportToPersistence, toDomainFromList: mapComplianceReportsFromList, createCategoryFromStat, estimateComplianceScore, };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sapientpants/deepsource-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server