canontra-0.1.0.0: src/Canontra/Fingerprint/Bundle.hs
{- |
Module : Canontra.Fingerprint.Bundle
Description : Orchestrator for all 8 polyglot fingerprint tiers and manifest construction.
This module unifies the full analysis pipeline for a given source unit across
Python, JavaScript, TypeScript, Go, and Rust. It runs parsing, normalization,
scope, call graph, control-flow (CFG), and data-flow (DFG) tier calculation.
-}
module Canontra.Fingerprint.Bundle
( computeBundle
, computeBundleAndProgram
, computeManifest
, computeBundleFromSource
, computeProgramFingerprints
, computeWholeRepoBundleFromHashes
) where
import qualified Data.ByteString as BS
import Data.Text (Text)
import qualified Data.Text.Encoding as TE
import Canontra.Fingerprint.CallGraph (computeFCG)
import Canontra.Fingerprint.Composite (computeF4)
import Canontra.Fingerprint.ControlFlow (computeFCF)
import Canontra.Fingerprint.DataFlow (computeFDF)
import Canontra.Fingerprint.Declaration (computeF2, extractDeclarations)
import Canontra.Fingerprint.Dependency (computeF3)
import Canontra.Fingerprint.Source (computeF0)
import Canontra.Fingerprint.Structural (computeF1)
import Canontra.Fingerprint.TypeContract (computeFT)
import Canontra.IR.Program (Program (..))
import Canontra.Normalize.Rules (engineName, engineVersion, normalizationVersion)
import Canontra.Parser.Polyglot (parsePolyglotSource)
import Canontra.Types
-- | Compute multi-tier fingerprint bundle directly from an IR 'Program'.
computeProgramFingerprints :: Program -> FingerprintBundle
computeProgramFingerprints prog =
let f0 = computeF1 prog
f1 = computeF1 prog
f2 = computeF2 prog
f3 = computeF3 prog
fcg = computeFCG prog
fcf = computeFCF prog
fdf = computeFDF prog
ft = computeFT prog
f4 = computeF4 f1 f2 f3 fcg fcf fdf ft
in FingerprintBundle f0 f1 f2 f3 fcg fcf fdf ft f4
computeBundleFromSource :: FilePath -> Text -> Either ParseError FingerprintBundle
computeBundleFromSource filePath src =
computeBundle filePath (TE.encodeUtf8 src) src
computeBundle :: FilePath -> BS.ByteString -> Text -> Either ParseError FingerprintBundle
computeBundle filePath rawBytes src =
fmap fst (computeBundleAndProgram filePath rawBytes src)
-- | Compute multi-tier fingerprint bundle and retain the parsed IR 'Program'.
computeBundleAndProgram :: FilePath -> BS.ByteString -> Text -> Either ParseError (FingerprintBundle, Program)
computeBundleAndProgram filePath rawBytes src = do
prog <- parsePolyglotSource filePath src
let f0 = computeF0 rawBytes
f1 = computeF1 prog
f2 = computeF2 prog
f3 = computeF3 prog
fcg = computeFCG prog
fcf = computeFCF prog
fdf = computeFDF prog
ft = computeFT prog
f4 = computeF4 f1 f2 f3 fcg fcf fdf ft
Right (FingerprintBundle f0 f1 f2 f3 fcg fcf fdf ft f4, prog)
computeManifest :: FilePath -> BS.ByteString -> Text -> Either ParseError Manifest
computeManifest filePath rawBytes src = do
prog@(Program modules lang) <- parsePolyglotSource filePath src
bundle <- computeBundle filePath rawBytes src
let decls = extractDeclarations prog
meta = ManifestMetadata
{ mmFileCount = 1
, mmModuleCount = length modules
, mmDeclarationCount = length decls
}
Right $ Manifest
{ mEngine = engineName
, mVersion = engineVersion
, mLanguage = lang
, mNormalizationVersion = normalizationVersion
, mHashAlgorithm = SHA256
, mFingerprints = bundle
, mMetadata = meta
}
-- | Compute whole-repository composite bundle from constituent repository hashes.
computeWholeRepoBundleFromHashes :: Fingerprint -> Fingerprint -> Fingerprint -> WholeRepoBundle
computeWholeRepoBundleFromHashes fr fwcg fwdf =
let combined = TE.encodeUtf8 (unFingerprint fr <> unFingerprint fwcg <> unFingerprint fwdf)
fw4 = computeF0 combined
in WholeRepoBundle fr fwcg fwdf fw4