sarif_rust 0.3.0

A comprehensive Rust library for parsing, generating, and manipulating SARIF (Static Analysis Results Interchange Format) v2.1.0 files
Documentation
//! SARIF extension and custom property support
//!
//! This module provides support for custom properties and tool-specific extensions.

use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// A property bag for holding arbitrary key-value pairs
pub type PropertyBag = HashMap<String, serde_json::Value>;

/// Extension information for SARIF objects
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Extension {
    /// The name of the extension
    pub name: String,

    /// The version of the extension
    pub version: Option<String>,

    /// Additional properties specific to this extension
    #[serde(flatten)]
    pub properties: Option<PropertyBag>,
}

impl Extension {
    /// Create a new extension
    pub fn new(name: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            version: None,
            properties: None,
        }
    }

    /// Set the version
    pub fn with_version(mut self, version: impl Into<String>) -> Self {
        self.version = Some(version.into());
        self
    }

    /// Add a custom property
    pub fn add_property(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
        self.properties
            .get_or_insert_with(HashMap::new)
            .insert(key.into(), value);
        self
    }
}

/// Helper trait for objects that can have custom properties
pub trait WithProperties {
    /// Add a custom property to this object
    fn add_property(&mut self, key: String, value: serde_json::Value);

    /// Get a custom property from this object
    fn get_property(&self, key: &str) -> Option<&serde_json::Value>;
}

/// Utility functions for working with property bags
pub mod property_utils {
    use super::*;

    /// Create a property bag with a single key-value pair
    pub fn single_property(key: impl Into<String>, value: serde_json::Value) -> PropertyBag {
        let mut bag = HashMap::new();
        bag.insert(key.into(), value);
        bag
    }

    /// Merge two property bags, with the second one taking precedence for duplicate keys
    pub fn merge_properties(mut base: PropertyBag, additional: PropertyBag) -> PropertyBag {
        base.extend(additional);
        base
    }

    /// Convert a string value to a JSON value
    pub fn string_value(value: impl Into<String>) -> serde_json::Value {
        serde_json::Value::String(value.into())
    }

    /// Convert a number to a JSON value
    pub fn number_value(value: impl Into<serde_json::Number>) -> serde_json::Value {
        serde_json::Value::Number(value.into())
    }

    /// Convert a boolean to a JSON value
    pub fn bool_value(value: bool) -> serde_json::Value {
        serde_json::Value::Bool(value)
    }

    /// Create an array JSON value
    pub fn array_value(values: Vec<serde_json::Value>) -> serde_json::Value {
        serde_json::Value::Array(values)
    }

    /// Create an object JSON value
    pub fn object_value(properties: PropertyBag) -> serde_json::Value {
        serde_json::Value::Object(properties.into_iter().collect())
    }
}