export type GraphNodeLike = { id: string; domain: string; }; export type GraphLinkLike = { source: string; target: string; }; export type ResourceGraphSnapshot = { nodes: GraphNodeLike[]; links: GraphLinkLike[]; meta: { resourceEid: string; resourceName: string; [key: string]: unknown; }; }; export type ProjectGraphSnapshot = { nodes: GraphNodeLike[]; links: GraphLinkLike[]; meta: { projectCode: string; projectName: string; [key: string]: unknown; }; }; function filterGraphData< TNode extends GraphNodeLike, TLink extends GraphLinkLike, >(input: { nodes: TNode[]; links: TLink[]; domain?: string; includeLinks?: boolean; }) { const requestedDomain = input.domain?.trim().toUpperCase(); const nodes = requestedDomain ? input.nodes.filter((node) => node.domain === requestedDomain) : input.nodes; const selectedNodeIds = new Set(nodes.map((node) => node.id)); const links = input.includeLinks ? input.links.filter((link) => selectedNodeIds.has(link.source) && selectedNodeIds.has(link.target)) : []; return { requestedDomain: requestedDomain ?? null, includedLinks: input.includeLinks ?? false, selectedNodeCount: nodes.length, selectedLinkCount: links.length, nodes, ...(input.includeLinks ? { links } : {}), }; } function getAvailableDomains(nodes: TNode[]) { return [...new Set(nodes.map((node) => node.domain))]; } export function formatResourceGraphDetail(input: { resourceId: string; graph: ResourceGraphSnapshot; domain?: string; includeLinks?: boolean; }) { return { resource: { id: input.resourceId, eid: input.graph.meta.resourceEid, displayName: input.graph.meta.resourceName, }, availableDomains: getAvailableDomains(input.graph.nodes), totalNodeCount: input.graph.nodes.length, totalLinkCount: input.graph.links.length, ...filterGraphData({ nodes: input.graph.nodes, links: input.graph.links, ...(input.domain ? { domain: input.domain } : {}), ...(input.includeLinks !== undefined ? { includeLinks: input.includeLinks } : {}), }), meta: input.graph.meta, }; } export function formatProjectGraphDetail(input: { projectId: string; graph: ProjectGraphSnapshot; domain?: string; includeLinks?: boolean; }) { return { project: { id: input.projectId, shortCode: input.graph.meta.projectCode, name: input.graph.meta.projectName, }, availableDomains: getAvailableDomains(input.graph.nodes), totalNodeCount: input.graph.nodes.length, totalLinkCount: input.graph.links.length, ...filterGraphData({ nodes: input.graph.nodes, links: input.graph.links, ...(input.domain ? { domain: input.domain } : {}), ...(input.includeLinks !== undefined ? { includeLinks: input.includeLinks } : {}), }), meta: input.graph.meta, }; }