ddex_builder/
lib.rs

1//! # DDEX Builder - Deterministic DDEX XML Generation
2//! 
3//! A high-performance, memory-safe DDEX XML builder that generates deterministic,
4//! byte-perfect XML using DB-C14N/1.0 canonicalization. Built in Rust with
5//! comprehensive security features and bindings for JavaScript, Python, and WebAssembly.
6//!
7//! ## Key Features
8//!
9//! - **🔒 Security First**: XXE protection, input validation, rate limiting, and comprehensive security measures
10//! - **⚡ High Performance**: Sub-millisecond generation for typical releases, memory-optimized streaming
11//! - **ðŸŽŊ Deterministic Output**: Guaranteed byte-perfect reproducibility using DB-C14N/1.0
12//! - **🔄 Round-trip Fidelity**: Perfect compatibility with ddex-parser for Parse → Build → Parse workflows
13//! - **🛠ïļ Partner Presets**: Pre-configured settings for Spotify, YouTube, Apple Music, and other platforms
14//! - **🌐 Multi-platform**: Native Rust, Node.js, Python, and WebAssembly bindings
15//! - **📊 Version Support**: Full support for ERN 3.8.2, 4.2, 4.3 with automatic conversion
16//!
17//! ## Quick Start
18//!
19//! ```rust
20//! use ddex_builder::{Builder, DdexVersion};
21//! use ddex_builder::builder::{BuildRequest, OutputFormat};
22//!
23//! // Create a builder with Spotify preset
24//! let mut builder = Builder::new();
25//! builder.preset("spotify_audio_43")?;
26//!
27//! // Build DDEX XML
28//! let request = BuildRequest {
29//!     source_xml: r#"<SoundRecording>...</SoundRecording>"#.to_string(),
30//!     output_format: OutputFormat::Xml,
31//!     preset: Some("spotify_audio_43".to_string()),
32//!     validate_schema: true,
33//! };
34//!
35//! let result = builder.build_internal(&request)?;
36//! println!("Generated DDEX XML: {}", result.xml);
37//! # Ok::<(), ddex_builder::BuildError>(())
38//! ```
39//!
40//! ## Security Features
41//!
42//! DDEX Builder includes comprehensive security measures:
43//!
44//! ```rust
45//! use ddex_builder::{InputValidator, SecurityConfig, ApiSecurityManager};
46//!
47//! // Configure security settings
48//! let security_config = SecurityConfig {
49//!     max_xml_size: 10_000_000,        // 10MB limit
50//!     max_json_depth: 32,              // Prevent deep nesting attacks
51//!     rate_limiting_enabled: true,
52//!     max_requests_per_minute: 100,
53//!     validate_urls: true,
54//!     block_private_ips: true,
55//!     ..Default::default()
56//! };
57//!
58//! // Validate inputs
59//! let validator = InputValidator::new(security_config.clone());
60//! validator.validate_xml_content(&xml_input)?;
61//!
62//! // API security management
63//! let mut api_security = ApiSecurityManager::new(security_config);
64//! api_security.validate_request("build", "client_id", xml_input.len())?;
65//! # Ok::<(), ddex_builder::BuildError>(())
66//! ```
67//!
68//! ## Architecture Overview
69//!
70//! ```text
71//! ┌─────────────────────────────────────────────────────────────────┐
72//! │                        DDEX Builder                             │
73//! ├─────────────────────────────────────────────────────────────────â”Ī
74//! │  Input Layer                                                    │
75//! │  ┌─────────────┐ ┌──────────────┐ ┌─────────────┐              │
76//! │  │ XML Parser  │ │ JSON Parser  │ │ Presets     │              │
77//! │  │ (Security)  │ │ (Validation) │ │ (Partners)  │              │
78//! │  └─────────────┘ └──────────────┘ └─────────────┘              │
79//! ├─────────────────────────────────────────────────────────────────â”Ī
80//! │  Processing Layer                                               │
81//! │  ┌─────────────┐ ┌──────────────┐ ┌─────────────┐              │
82//! │  │ AST Builder │ │ Reference    │ │ Version     │              │
83//! │  │ (Elements)  │ │ Linker       │ │ Converter   │              │
84//! │  └─────────────┘ └──────────────┘ └─────────────┘              │
85//! ├─────────────────────────────────────────────────────────────────â”Ī
86//! │  Output Layer                                                   │
87//! │  ┌─────────────┐ ┌──────────────┐ ┌─────────────┐              │
88//! │  │ XML         │ │ DB-C14N      │ │ Output      │              │
89//! │  │ Generator   │ │ Canonicalize │ │ Sanitizer   │              │
90//! │  └─────────────┘ └──────────────┘ └─────────────┘              │
91//! └─────────────────────────────────────────────────────────────────┘
92//! ```
93//!
94//! ## Performance Characteristics
95//!
96//! - **Parse 10KB**: <5ms
97//! - **Parse 100KB**: <10ms  
98//! - **Parse 1MB**: <50ms
99//! - **Build typical release**: <15ms
100//! - **Memory usage**: <50MB for large files with streaming
101//! - **WASM bundle size**: <500KB
102//!
103//! ## Version Support
104//!
105//! | DDEX Version | Support Level | Notes |
106//! |--------------|---------------|-------|
107//! | ERN 3.8.2    | ✅ Full       | Legacy support |
108//! | ERN 4.2      | ✅ Full       | Enhanced features |
109//! | ERN 4.3      | ✅ Full       | Latest standard |
110//!
111//! ## Partner Presets
112//!
113//! Pre-configured settings for major platforms:
114//!
115//! - `spotify_audio_43` - Spotify audio releases (ERN 4.3)
116//! - `youtube_video_43` - YouTube video content (ERN 4.3)
117//! - `apple_music_43` - Apple Music releases (ERN 4.3)
118//! - `universal_basic` - Universal Music basic preset
119//! - `sony_enhanced` - Sony Music enhanced features
120//!
121//! See the [User Guide](https://docs.ddex-builder.io/user-guide) for detailed preset documentation.
122
123#![forbid(unsafe_code)]
124#![warn(missing_docs)]
125
126pub mod ast;
127pub mod builder;
128pub mod canonical;
129pub mod determinism;
130pub mod error;
131pub mod guarantees;
132pub mod generator;
133pub mod presets;
134pub mod streaming;
135pub mod diff;
136pub mod messages;
137pub mod linker;
138pub mod id_generator;
139pub mod preflight;
140pub mod schema;
141pub mod versions;
142pub mod optimized_strings;
143pub mod memory_optimization;
144pub mod parallel_processing;
145pub mod caching;
146pub mod security;
147pub mod api_security;
148pub mod namespace_minimizer;
149pub mod fidelity;
150pub mod verification;
151pub mod round_trip;
152
153// Re-export main types
154pub use builder::{DDEXBuilder, BuildOptions, BuildRequest, BuildResult};
155pub use canonical::DB_C14N;
156pub use determinism::DeterminismConfig;
157pub use error::{BuildError, BuildWarning};
158pub use guarantees::{DeterminismGuarantee, DeterminismGuaranteeValidator, GuaranteeReport};
159pub use presets::PartnerPreset;
160pub use linker::{ReferenceLinker, LinkerConfig, EntityType, LinkerError};
161pub use id_generator::{StableHashGenerator, StableHashConfig, HashAlgorithm};
162pub use preflight::{PreflightValidator, ValidationConfig, ValidationResult, PreflightLevel};
163pub use diff::{DiffEngine, DiffConfig, VersionCompatibility};
164pub use diff::types::{ChangeSet, SemanticChange, DiffPath, ChangeType, ImpactLevel};
165pub use diff::formatter::DiffFormatter;
166pub use messages::{UpdateReleaseMessage, UpdateGenerator, UpdateAction, UpdateConfig, ValidationStatus};
167pub use schema::{SchemaGenerator, JsonSchema, SchemaConfig, SchemaDraft, SchemaCommand};
168pub use versions::{VersionManager, VersionConverter, ConverterResult as ConversionResult, ConversionOptions};
169pub use presets::DdexVersion;
170
171// Security module exports
172pub use security::{InputValidator, SecurityConfig, RateLimiter, SecureTempFile, OutputSanitizer};
173pub use api_security::{ApiSecurityManager, ApiSecurityConfig, FfiDataType, BatchStats};
174
175// Perfect Fidelity Engine exports
176pub use fidelity::{FidelityConfig, PreservationLevel, FidelityStatistics};
177pub use verification::{BuildVerifier, VerificationStatistics};
178pub use round_trip::{RoundTripTester, FidelityAnalysis};
179
180use indexmap::IndexMap;
181use serde::{Deserialize, Serialize};
182use std::time::Duration;
183use std::collections::HashMap;
184
185/// Version of the DB-C14N specification
186pub const DB_C14N_VERSION: &str = "1.0";
187
188/// Perfect Fidelity Engine configuration options
189#[derive(Debug, Clone, Serialize, Deserialize)]
190pub struct FidelityOptions {
191    /// Enable perfect round-trip fidelity preservation
192    pub enable_perfect_fidelity: bool,
193    /// Preserve all XML comments in their original positions
194    pub preserve_comments: bool,
195    /// Preserve processing instructions
196    pub preserve_processing_instructions: bool,
197    /// Preserve unknown/extension elements and attributes
198    pub preserve_extensions: bool,
199    /// Preserve original attribute ordering when possible
200    pub preserve_attribute_order: bool,
201    /// Preserve namespace prefixes from input
202    pub preserve_namespace_prefixes: bool,
203    /// Canonicalization algorithm to use
204    pub canonicalization: CanonicalizationAlgorithm,
205    /// Custom canonicalization rules (used with Custom algorithm)
206    pub custom_canonicalization_rules: Option<CustomCanonicalizationRules>,
207    /// Enable deterministic element ordering
208    pub enable_deterministic_ordering: bool,
209    /// Collect detailed building statistics
210    pub collect_statistics: bool,
211    /// Enable build verification (double-check output)
212    pub enable_verification: bool,
213    /// Verification configuration
214    pub verification_config: VerificationConfig,
215}
216
217impl Default for FidelityOptions {
218    fn default() -> Self {
219        Self {
220            enable_perfect_fidelity: false,
221            preserve_comments: false,
222            preserve_processing_instructions: false,
223            preserve_extensions: true,
224            preserve_attribute_order: false,
225            preserve_namespace_prefixes: false,
226            canonicalization: CanonicalizationAlgorithm::DbC14N,
227            custom_canonicalization_rules: None,
228            enable_deterministic_ordering: true,
229            collect_statistics: false,
230            enable_verification: false,
231            verification_config: VerificationConfig::default(),
232        }
233    }
234}
235
236/// Canonicalization algorithms supported by the Perfect Fidelity Engine
237#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
238pub enum CanonicalizationAlgorithm {
239    /// No canonicalization (preserves exact formatting)
240    None,
241    /// XML Canonicalization Version 1.0 (W3C C14N)
242    C14N,
243    /// XML Canonicalization Version 1.1 (W3C C14N11)
244    C14N11,
245    /// DDEX-specific DB-C14N/1.0 algorithm (default)
246    DbC14N,
247    /// Custom canonicalization with user-defined rules
248    Custom(CustomCanonicalizationRules),
249}
250
251/// Custom canonicalization rules for specialized use cases
252#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
253pub struct CustomCanonicalizationRules {
254    /// Preserve whitespace between elements
255    pub preserve_whitespace: bool,
256    /// Sort attributes alphabetically
257    pub sort_attributes: bool,
258    /// Normalize line endings to LF
259    pub normalize_line_endings: bool,
260    /// Remove redundant namespace declarations
261    pub minimize_namespaces: bool,
262    /// Custom attribute ordering rules
263    pub attribute_ordering: Vec<String>,
264    /// Custom element ordering rules
265    pub element_ordering: HashMap<String, Vec<String>>,
266}
267
268impl Default for CustomCanonicalizationRules {
269    fn default() -> Self {
270        Self {
271            preserve_whitespace: false,
272            sort_attributes: true,
273            normalize_line_endings: true,
274            minimize_namespaces: true,
275            attribute_ordering: Vec::new(),
276            element_ordering: HashMap::new(),
277        }
278    }
279}
280
281/// Build verification configuration
282#[derive(Debug, Clone, Serialize, Deserialize)]
283pub struct VerificationConfig {
284    /// Enable round-trip verification (build -> parse -> build)
285    pub enable_round_trip_verification: bool,
286    /// Enable canonicalization verification
287    pub enable_canonicalization_verification: bool,
288    /// Enable schema validation after build
289    pub enable_schema_validation: bool,
290    /// Enable determinism verification (multiple builds identical)
291    pub enable_determinism_verification: bool,
292    /// Number of builds for determinism verification
293    pub determinism_test_iterations: usize,
294    /// Timeout for verification operations
295    pub verification_timeout: Duration,
296}
297
298impl Default for VerificationConfig {
299    fn default() -> Self {
300        Self {
301            enable_round_trip_verification: true,
302            enable_canonicalization_verification: true,
303            enable_schema_validation: false,
304            enable_determinism_verification: true,
305            determinism_test_iterations: 3,
306            verification_timeout: Duration::from_secs(30),
307        }
308    }
309}
310
311/// Build verification result
312#[derive(Debug, Clone, Serialize, Deserialize)]
313pub struct VerificationResult {
314    /// Overall verification success
315    pub success: bool,
316    /// Round-trip verification result
317    pub round_trip_success: bool,
318    /// Canonicalization verification result
319    pub canonicalization_success: bool,
320    /// Schema validation result
321    pub schema_validation_success: bool,
322    /// Determinism verification result
323    pub determinism_success: bool,
324    /// Verification errors and warnings
325    pub issues: Vec<VerificationIssue>,
326    /// Time taken for verification
327    pub verification_time: Duration,
328}
329
330/// Verification issue (error or warning)
331#[derive(Debug, Clone, Serialize, Deserialize)]
332pub struct VerificationIssue {
333    /// Issue severity
334    pub severity: VerificationSeverity,
335    /// Issue category
336    pub category: String,
337    /// Human-readable message
338    pub message: String,
339    /// Optional path to the problematic element
340    pub path: Option<String>,
341    /// Optional suggestion for fixing
342    pub suggestion: Option<String>,
343}
344
345/// Verification issue severity
346#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
347pub enum VerificationSeverity {
348    /// Error that prevents successful verification
349    Error,
350    /// Warning that may indicate a problem
351    Warning,
352    /// Informational message
353    Info,
354}
355
356/// Building statistics collected during the build process
357#[derive(Debug, Clone, Serialize, Deserialize)]
358pub struct BuildStatistics {
359    /// Total build time
360    pub build_time: Duration,
361    /// Time spent on canonicalization
362    pub canonicalization_time: Duration,
363    /// Time spent on validation
364    pub validation_time: Duration,
365    /// Time spent on verification
366    pub verification_time: Duration,
367    /// Peak memory usage during build
368    pub peak_memory_bytes: usize,
369    /// Number of elements processed
370    pub element_count: usize,
371    /// Number of attributes processed
372    pub attribute_count: usize,
373    /// Size of input data
374    pub input_size_bytes: usize,
375    /// Size of output data
376    pub output_size_bytes: usize,
377    /// Number of namespaces processed
378    pub namespace_count: usize,
379    /// Number of comments preserved
380    pub comment_count: usize,
381    /// Number of processing instructions preserved
382    pub processing_instruction_count: usize,
383}
384
385impl Default for BuildStatistics {
386    fn default() -> Self {
387        Self {
388            build_time: Duration::ZERO,
389            canonicalization_time: Duration::ZERO,
390            validation_time: Duration::ZERO,
391            verification_time: Duration::ZERO,
392            peak_memory_bytes: 0,
393            element_count: 0,
394            attribute_count: 0,
395            input_size_bytes: 0,
396            output_size_bytes: 0,
397            namespace_count: 0,
398            comment_count: 0,
399            processing_instruction_count: 0,
400        }
401    }
402}
403
404/// The main DDEX Builder for creating deterministic XML output.
405///
406/// `Builder` is the primary interface for generating DDEX-compliant XML with
407/// guaranteed deterministic output. It supports partner presets, version conversion,
408/// and comprehensive security features.
409///
410/// ## Features
411///
412/// - **Deterministic Output**: Uses DB-C14N/1.0 for byte-perfect reproducibility
413/// - **Partner Presets**: Pre-configured settings for major music platforms
414/// - **Version Management**: Support for ERN 3.8.2, 4.2, and 4.3 with conversion
415/// - **Security**: Built-in validation, rate limiting, and XXE protection
416/// - **Performance**: Memory-optimized with streaming support for large files
417///
418/// ## Usage Patterns
419///
420/// ### Basic Usage
421///
422/// ```rust
423/// use ddex_builder::Builder;
424///
425/// let builder = Builder::new();
426/// let available_presets = builder.available_presets();
427/// println!("Available presets: {:?}", available_presets);
428/// ```
429///
430/// ### With Partner Preset
431///
432/// ```rust
433/// use ddex_builder::Builder;
434///
435/// let mut builder = Builder::new();
436/// builder.preset("spotify_audio_43")?;
437/// 
438/// // Builder is now configured for Spotify Audio releases (ERN 4.3)
439/// assert!(builder.is_preset_locked() == false); // Unlocked for further customization
440/// # Ok::<(), ddex_builder::BuildError>(())
441/// ```
442///
443/// ### Locked Preset Configuration
444///
445/// ```rust
446/// use ddex_builder::Builder;
447///
448/// let mut builder = Builder::new();
449/// builder.apply_preset("spotify_audio_43", true)?; // Lock the preset
450/// 
451/// assert!(builder.is_preset_locked());
452/// # Ok::<(), ddex_builder::BuildError>(())
453/// ```
454///
455/// ### Version Conversion
456///
457/// ```rust
458/// use ddex_builder::{Builder, DdexVersion};
459/// use ddex_builder::versions::ConversionOptions;
460///
461/// let builder = Builder::new();
462/// 
463/// // Check version compatibility
464/// let compatible = builder.is_version_compatible(
465///     DdexVersion::Ern382, 
466///     DdexVersion::Ern43
467/// );
468/// 
469/// if compatible {
470///     let options = Some(ConversionOptions::default());
471///     let result = builder.convert_version(
472///         &xml_content,
473///         DdexVersion::Ern382,
474///         DdexVersion::Ern43,
475///         options
476///     )?;
477///     println!("Converted XML: {}", result.converted_xml);
478/// }
479/// # let xml_content = "<test></test>";
480/// # Ok::<(), ddex_builder::BuildError>(())
481/// ```
482///
483/// ## Thread Safety
484///
485/// `Builder` is `Send + Sync` and can be safely shared between threads.
486/// Each thread should create its own instance for best performance.
487///
488/// ## Memory Usage
489///
490/// The builder uses memory-optimized data structures and streaming
491/// where possible. Typical memory usage:
492/// - Small releases (<100KB): ~5MB
493/// - Large releases (>1MB): ~20-50MB with streaming
494#[derive(Debug, Clone)]
495pub struct Builder {
496    config: DeterminismConfig,
497    presets: IndexMap<String, PartnerPreset>,
498    locked_preset: Option<String>,
499    version_manager: versions::VersionManager,
500    target_version: Option<DdexVersion>,
501    fidelity_options: FidelityOptions,
502    verification_config: VerificationConfig,
503}
504
505impl Default for Builder {
506    fn default() -> Self {
507        Self::new()
508    }
509}
510
511impl Builder {
512    /// Creates a new DDEX Builder with default configuration.
513    ///
514    /// The builder is initialized with:
515    /// - Default determinism configuration for byte-perfect output
516    /// - All available partner presets loaded
517    /// - No preset locked (can be changed)
518    /// - Latest supported DDEX version as target
519    ///
520    /// # Examples
521    ///
522    /// ```rust
523    /// use ddex_builder::Builder;
524    ///
525    /// let builder = Builder::new();
526    /// assert!(!builder.is_preset_locked());
527    /// assert!(builder.available_presets().len() > 0);
528    /// ```
529    ///
530    /// # Performance
531    /// 
532    /// Creating a new builder is fast (~1Ξs) as presets are loaded from
533    /// embedded configuration data.
534    pub fn new() -> Self {
535        Self {
536            config: DeterminismConfig::default(),
537            presets: Self::load_default_presets(),
538            locked_preset: None,
539            version_manager: versions::VersionManager::new(),
540            target_version: None,
541            fidelity_options: FidelityOptions::default(),
542            verification_config: VerificationConfig::default(),
543        }
544    }
545    
546    /// Create builder with custom configuration
547    pub fn with_config(config: DeterminismConfig) -> Self {
548        Self {
549            config,
550            presets: Self::load_default_presets(),
551            locked_preset: None,
552            version_manager: versions::VersionManager::new(),
553            target_version: None,
554            fidelity_options: FidelityOptions::default(),
555            verification_config: VerificationConfig::default(),
556        }
557    }
558    
559    /// Create builder with Perfect Fidelity Engine enabled
560    pub fn with_perfect_fidelity() -> Self {
561        let mut fidelity_options = FidelityOptions::default();
562        fidelity_options.enable_perfect_fidelity = true;
563        fidelity_options.preserve_comments = true;
564        fidelity_options.preserve_processing_instructions = true;
565        fidelity_options.preserve_extensions = true;
566        fidelity_options.preserve_attribute_order = true;
567        fidelity_options.preserve_namespace_prefixes = true;
568        fidelity_options.enable_verification = true;
569        
570        Self {
571            config: DeterminismConfig::default(),
572            presets: Self::load_default_presets(),
573            locked_preset: None,
574            version_manager: versions::VersionManager::new(),
575            target_version: None,
576            fidelity_options,
577            verification_config: VerificationConfig::default(),
578        }
579    }
580    
581    /// Create builder with custom fidelity options
582    pub fn with_fidelity_options(fidelity_options: FidelityOptions) -> Self {
583        Self {
584            config: DeterminismConfig::default(),
585            presets: Self::load_default_presets(),
586            locked_preset: None,
587            version_manager: versions::VersionManager::new(),
588            target_version: None,
589            fidelity_options,
590            verification_config: VerificationConfig::default(),
591        }
592    }
593    
594    /// Create builder optimized for round-trip operations
595    pub fn for_round_trip() -> Self {
596        let mut fidelity_options = FidelityOptions::default();
597        fidelity_options.enable_perfect_fidelity = true;
598        fidelity_options.preserve_comments = true;
599        fidelity_options.preserve_processing_instructions = true;
600        fidelity_options.preserve_extensions = true;
601        fidelity_options.preserve_attribute_order = true;
602        fidelity_options.preserve_namespace_prefixes = true;
603        fidelity_options.canonicalization = CanonicalizationAlgorithm::DbC14N;
604        fidelity_options.enable_verification = true;
605        fidelity_options.collect_statistics = true;
606        
607        let mut verification_config = VerificationConfig::default();
608        verification_config.enable_round_trip_verification = true;
609        verification_config.enable_canonicalization_verification = true;
610        verification_config.enable_determinism_verification = true;
611        
612        Self {
613            config: DeterminismConfig::default(),
614            presets: Self::load_default_presets(),
615            locked_preset: None,
616            version_manager: versions::VersionManager::new(),
617            target_version: None,
618            fidelity_options,
619            verification_config,
620        }
621    }
622    
623    /// Applies a partner preset configuration to the builder.
624    ///
625    /// Presets contain pre-configured settings optimized for specific music platforms
626    /// and distribution partners. Each preset includes determinism settings, validation
627    /// rules, and format preferences.
628    ///
629    /// # Arguments
630    ///
631    /// * `preset_name` - Name of the preset to apply (see [`available_presets`])
632    /// * `lock` - Whether to lock the preset to prevent further modifications
633    ///
634    /// # Returns
635    ///
636    /// * `Ok(())` - Preset applied successfully
637    /// * `Err(BuildError::InvalidFormat)` - Unknown preset name
638    ///
639    /// # Examples
640    ///
641    /// ```rust
642    /// use ddex_builder::Builder;
643    ///
644    /// let mut builder = Builder::new();
645    ///
646    /// // Apply Spotify preset without locking
647    /// builder.apply_preset("spotify_audio_43", false)?;
648    /// assert!(!builder.is_preset_locked());
649    ///
650    /// // Apply and lock YouTube preset  
651    /// builder.apply_preset("youtube_video_43", true)?;
652    /// assert!(builder.is_preset_locked());
653    /// # Ok::<(), ddex_builder::BuildError>(())
654    /// ```
655    ///
656    /// # Available Presets
657    ///
658    /// Common presets include:
659    /// - `spotify_audio_43` - Spotify audio releases (ERN 4.3)
660    /// - `youtube_video_43` - YouTube video content (ERN 4.3)  
661    /// - `apple_music_43` - Apple Music releases (ERN 4.3)
662    /// - `universal_basic` - Universal Music basic preset
663    /// - `sony_enhanced` - Sony Music enhanced features
664    ///
665    /// Use [`available_presets`] to get the complete list.
666    ///
667    /// [`available_presets`]: Self::available_presets
668    pub fn apply_preset(&mut self, preset_name: &str, lock: bool) -> Result<(), error::BuildError> {
669        let preset = self.presets.get(preset_name)
670            .ok_or_else(|| error::BuildError::InvalidFormat {
671                field: "preset".to_string(),
672                message: format!("Unknown preset: {}", preset_name),
673            })?
674            .clone();
675        
676        // Apply the preset's determinism config
677        self.config = preset.determinism;
678        
679        // Lock the preset if requested
680        if lock {
681            self.locked_preset = Some(preset_name.to_string());
682        }
683        
684        Ok(())
685    }
686
687    /// Apply a preset configuration (alias for apply_preset for convenience)
688    pub fn preset(&mut self, preset_name: &str) -> Result<&mut Self, error::BuildError> {
689        self.apply_preset(preset_name, false)?;
690        Ok(self)
691    }
692
693    /// Get available preset names
694    pub fn available_presets(&self) -> Vec<String> {
695        self.presets.keys().cloned().collect()
696    }
697
698    /// Get preset details
699    pub fn get_preset(&self, preset_name: &str) -> Option<&PartnerPreset> {
700        self.presets.get(preset_name)
701    }
702    
703    /// Check if a preset is locked
704    pub fn is_preset_locked(&self) -> bool {
705        self.locked_preset.is_some()
706    }
707    
708    /// Get the current configuration
709    pub fn config(&self) -> &DeterminismConfig {
710        &self.config
711    }
712    
713    /// Get the current fidelity options
714    pub fn fidelity_options(&self) -> &FidelityOptions {
715        &self.fidelity_options
716    }
717    
718    /// Set fidelity options
719    pub fn set_fidelity_options(&mut self, options: FidelityOptions) -> &mut Self {
720        self.fidelity_options = options;
721        self
722    }
723    
724    /// Enable Perfect Fidelity Engine with default settings
725    pub fn enable_perfect_fidelity(&mut self) -> &mut Self {
726        self.fidelity_options.enable_perfect_fidelity = true;
727        self.fidelity_options.preserve_comments = true;
728        self.fidelity_options.preserve_processing_instructions = true;
729        self.fidelity_options.preserve_extensions = true;
730        self.fidelity_options.preserve_attribute_order = true;
731        self.fidelity_options.preserve_namespace_prefixes = true;
732        self.fidelity_options.enable_verification = true;
733        self
734    }
735    
736    /// Disable Perfect Fidelity Engine
737    pub fn disable_perfect_fidelity(&mut self) -> &mut Self {
738        self.fidelity_options.enable_perfect_fidelity = false;
739        self.fidelity_options.preserve_comments = false;
740        self.fidelity_options.preserve_processing_instructions = false;
741        self.fidelity_options.preserve_attribute_order = false;
742        self.fidelity_options.preserve_namespace_prefixes = false;
743        self.fidelity_options.enable_verification = false;
744        self
745    }
746    
747    /// Set canonicalization algorithm
748    pub fn with_canonicalization(&mut self, algorithm: CanonicalizationAlgorithm) -> &mut Self {
749        self.fidelity_options.canonicalization = algorithm;
750        self
751    }
752    
753    /// Enable DB-C14N/1.0 canonicalization (default for DDEX)
754    pub fn with_db_c14n(&mut self) -> &mut Self {
755        self.fidelity_options.canonicalization = CanonicalizationAlgorithm::DbC14N;
756        self
757    }
758    
759    /// Enable standard XML C14N canonicalization
760    pub fn with_c14n(&mut self) -> &mut Self {
761        self.fidelity_options.canonicalization = CanonicalizationAlgorithm::C14N;
762        self
763    }
764    
765    /// Enable XML C14N 1.1 canonicalization
766    pub fn with_c14n11(&mut self) -> &mut Self {
767        self.fidelity_options.canonicalization = CanonicalizationAlgorithm::C14N11;
768        self
769    }
770    
771    /// Set custom canonicalization rules
772    pub fn with_custom_canonicalization(&mut self, rules: CustomCanonicalizationRules) -> &mut Self {
773        self.fidelity_options.canonicalization = CanonicalizationAlgorithm::Custom(rules.clone());
774        self.fidelity_options.custom_canonicalization_rules = Some(rules);
775        self
776    }
777    
778    /// Enable build verification
779    pub fn with_verification(&mut self, config: VerificationConfig) -> &mut Self {
780        self.fidelity_options.enable_verification = true;
781        self.verification_config = config;
782        self
783    }
784    
785    /// Enable statistics collection
786    pub fn with_statistics(&mut self) -> &mut Self {
787        self.fidelity_options.collect_statistics = true;
788        self
789    }
790    
791    /// Check if Perfect Fidelity Engine is enabled
792    pub fn is_perfect_fidelity_enabled(&self) -> bool {
793        self.fidelity_options.enable_perfect_fidelity
794    }
795    
796    /// Get current canonicalization algorithm
797    pub fn canonicalization_algorithm(&self) -> &CanonicalizationAlgorithm {
798        &self.fidelity_options.canonicalization
799    }
800    
801    /// Set target DDEX version for building
802    pub fn with_version(&mut self, version: DdexVersion) -> &mut Self {
803        self.target_version = Some(version);
804        self
805    }
806    
807    /// Get the target DDEX version
808    pub fn target_version(&self) -> Option<DdexVersion> {
809        self.target_version
810    }
811    
812    /// Detect version from XML content
813    pub fn detect_version(&self, xml_content: &str) -> Result<DdexVersion, error::BuildError> {
814        self.version_manager.detect_version(xml_content)
815            .map(|detection| detection.detected_version)
816            .map_err(|e| error::BuildError::InvalidFormat {
817                field: "version".to_string(),
818                message: format!("Version detection failed: {}", e),
819            })
820    }
821    
822    /// Convert XML between DDEX versions
823    pub fn convert_version(&self, xml_content: &str, from_version: DdexVersion, to_version: DdexVersion, options: Option<ConversionOptions>) -> Result<versions::ConverterResult, error::BuildError> {
824        let converter = versions::VersionConverter::new();
825        Ok(converter.convert(xml_content, from_version, to_version, options))
826    }
827    
828    /// Get version compatibility information
829    pub fn is_version_compatible(&self, from: DdexVersion, to: DdexVersion) -> bool {
830        self.version_manager.is_conversion_supported(from, to)
831    }
832    
833    /// Get supported DDEX versions
834    pub fn supported_versions(&self) -> Vec<DdexVersion> {
835        versions::utils::supported_versions()
836    }
837    
838    fn load_default_presets() -> IndexMap<String, PartnerPreset> {
839        presets::all_presets()
840    }
841    
842    /// Build DDEX XML with Perfect Fidelity Engine
843    pub fn build_with_fidelity(&self, request: &builder::BuildRequest) -> Result<FidelityBuildResult, error::BuildError> {
844        let start_time = std::time::Instant::now();
845        let mut statistics = BuildStatistics::default();
846        
847        // Use the existing build options structure
848        let build_options = builder::BuildOptions::default();
849        
850        // Build the XML using existing builder
851        let ddex_builder = builder::DDEXBuilder::new();
852        let build_result = ddex_builder.build(request.clone(), build_options)?;
853        
854        statistics.build_time = start_time.elapsed();
855        statistics.output_size_bytes = build_result.xml.len();
856        
857        // Perform verification if enabled
858        let verification_result = if self.fidelity_options.enable_verification {
859            // Convert lib VerificationConfig to verification VerificationConfig
860            let verification_config = verification::VerificationConfig {
861                enable_round_trip_verification: self.verification_config.enable_round_trip_verification,
862                enable_canonicalization_verification: self.verification_config.enable_canonicalization_verification,
863                enable_schema_validation: self.verification_config.enable_schema_validation,
864                enable_determinism_verification: self.verification_config.enable_determinism_verification,
865                determinism_test_iterations: self.verification_config.determinism_test_iterations,
866                verification_timeout: self.verification_config.verification_timeout,
867            };
868            let verifier = verification::BuildVerifier::new(verification_config);
869            let result = verifier.verify(&build_result.xml, &self.fidelity_options)?;
870            
871            // Convert verification::VerificationResult to VerificationResult
872            Some(VerificationResult {
873                success: result.success,
874                round_trip_success: result.round_trip_success,
875                canonicalization_success: result.canonicalization_success,
876                determinism_success: result.determinism_success,
877                schema_validation_success: result.schema_validation_success,
878                issues: result.issues.into_iter().map(|issue| VerificationIssue {
879                    category: issue.category,
880                    severity: match issue.severity {
881                        verification::VerificationSeverity::Error => VerificationSeverity::Error,
882                        verification::VerificationSeverity::Warning => VerificationSeverity::Warning,
883                        verification::VerificationSeverity::Info => VerificationSeverity::Info,
884                    },
885                    message: issue.message,
886                    path: issue.path,
887                    suggestion: issue.suggestion,
888                }).collect(),
889                verification_time: result.verification_time,
890            })
891        } else {
892            None
893        };
894        
895        Ok(FidelityBuildResult {
896            xml: build_result.xml,
897            statistics: if self.fidelity_options.collect_statistics {
898                Some(statistics)
899            } else {
900                None
901            },
902            verification_result,
903            canonicalization_applied: self.fidelity_options.canonicalization != CanonicalizationAlgorithm::None,
904            db_c14n_version: if self.fidelity_options.canonicalization == CanonicalizationAlgorithm::DbC14N {
905                Some(DB_C14N_VERSION.to_string())
906            } else {
907                None
908            },
909        })
910    }
911    
912    /// Verify build output meets fidelity requirements
913    pub fn verify_build(&self, xml_output: &str) -> Result<VerificationResult, error::BuildError> {
914        // Convert lib VerificationConfig to verification VerificationConfig
915        let verification_config = verification::VerificationConfig {
916            enable_round_trip_verification: self.verification_config.enable_round_trip_verification,
917            enable_canonicalization_verification: self.verification_config.enable_canonicalization_verification,
918            enable_schema_validation: self.verification_config.enable_schema_validation,
919            enable_determinism_verification: self.verification_config.enable_determinism_verification,
920            determinism_test_iterations: self.verification_config.determinism_test_iterations,
921            verification_timeout: self.verification_config.verification_timeout,
922        };
923        
924        let verifier = verification::BuildVerifier::new(verification_config);
925        let result = verifier.verify(xml_output, &self.fidelity_options)?;
926        
927        // Convert verification::VerificationResult to VerificationResult
928        Ok(VerificationResult {
929            success: result.success,
930            round_trip_success: result.round_trip_success,
931            canonicalization_success: result.canonicalization_success,
932            determinism_success: result.determinism_success,
933            schema_validation_success: result.schema_validation_success,
934            issues: result.issues.into_iter().map(|issue| VerificationIssue {
935                category: issue.category,
936                severity: match issue.severity {
937                    verification::VerificationSeverity::Error => VerificationSeverity::Error,
938                    verification::VerificationSeverity::Warning => VerificationSeverity::Warning,
939                    verification::VerificationSeverity::Info => VerificationSeverity::Info,
940                },
941                message: issue.message,
942                path: issue.path,
943                suggestion: issue.suggestion,
944            }).collect(),
945            verification_time: result.verification_time,
946        })
947    }
948    
949    /// Test round-trip fidelity: XML → Parse → Build → Parse → Compare
950    pub fn test_round_trip_fidelity(&self, original_xml: &str) -> Result<RoundTripResult, error::BuildError> {
951        let round_trip = round_trip::RoundTripTester::new(self.fidelity_options.clone());
952        let result = round_trip.test_round_trip(original_xml)?;
953        
954        // Convert round_trip::RoundTripResult to RoundTripResult
955        Ok(RoundTripResult {
956            success: result.success,
957            original_xml: result.original_xml,
958            rebuilt_xml: result.rebuilt_xml,
959            byte_identical: result.byte_identical,
960            differences: result.differences,
961            test_time: result.test_time,
962        })
963    }
964    
965    /// Canonicalize XML using the configured algorithm
966    pub fn canonicalize(&self, xml_content: &str) -> Result<String, error::BuildError> {
967        match &self.fidelity_options.canonicalization {
968            CanonicalizationAlgorithm::None => Ok(xml_content.to_string()),
969            CanonicalizationAlgorithm::C14N => {
970                // TODO: Implement C14N canonicalization
971                Ok(xml_content.to_string())
972            },
973            CanonicalizationAlgorithm::C14N11 => {
974                // TODO: Implement C14N11 canonicalization
975                Ok(xml_content.to_string())
976            },
977            CanonicalizationAlgorithm::DbC14N => {
978                // TODO: Implement DB-C14N canonicalization using canonical module
979                Ok(xml_content.to_string())
980            },
981            CanonicalizationAlgorithm::Custom(rules) => {
982                // TODO: Implement custom canonicalization
983                let _ = rules; // Avoid unused parameter warning
984                Ok(xml_content.to_string())
985            },
986        }
987    }
988    
989    /// Get DB-C14N/1.0 configuration details
990    pub fn db_c14n_config(&self) -> DbC14NConfig {
991        DbC14NConfig {
992            version: DB_C14N_VERSION.to_string(),
993            algorithm: self.fidelity_options.canonicalization.clone(),
994            deterministic_ordering: self.fidelity_options.enable_deterministic_ordering,
995            preserve_comments: self.fidelity_options.preserve_comments,
996            preserve_processing_instructions: self.fidelity_options.preserve_processing_instructions,
997            namespace_handling: if self.fidelity_options.preserve_namespace_prefixes {
998                NamespaceHandling::Preserve
999            } else {
1000                NamespaceHandling::Minimize
1001            },
1002        }
1003    }
1004    
1005    /// Internal build method used by determinism verifier
1006    pub(crate) fn build_internal(&self, request: &builder::BuildRequest) -> Result<builder::BuildResult, error::BuildError> {
1007        let ddex_builder = builder::DDEXBuilder::new();
1008        let build_options = builder::BuildOptions::default();
1009        
1010        ddex_builder.build(request.clone(), build_options)
1011    }
1012}
1013
1014/// Perfect Fidelity Engine build result
1015#[derive(Debug, Clone, Serialize, Deserialize)]
1016pub struct FidelityBuildResult {
1017    /// Generated XML output
1018    pub xml: String,
1019    /// Build statistics (if enabled)
1020    pub statistics: Option<BuildStatistics>,
1021    /// Verification result (if enabled)
1022    pub verification_result: Option<VerificationResult>,
1023    /// Whether canonicalization was applied
1024    pub canonicalization_applied: bool,
1025    /// DB-C14N version used (if applicable)
1026    pub db_c14n_version: Option<String>,
1027}
1028
1029/// Round-trip test result
1030#[derive(Debug, Clone, Serialize, Deserialize)]
1031pub struct RoundTripResult {
1032    /// Whether round-trip was successful
1033    pub success: bool,
1034    /// Original XML input
1035    pub original_xml: String,
1036    /// XML after build process
1037    pub rebuilt_xml: String,
1038    /// Whether XMLs are byte-identical after canonicalization
1039    pub byte_identical: bool,
1040    /// Differences found (if any)
1041    pub differences: Vec<String>,
1042    /// Time taken for round-trip test
1043    pub test_time: Duration,
1044}
1045
1046/// DB-C14N/1.0 configuration
1047#[derive(Debug, Clone, Serialize, Deserialize)]
1048pub struct DbC14NConfig {
1049    /// DB-C14N specification version
1050    pub version: String,
1051    /// Canonicalization algorithm in use
1052    pub algorithm: CanonicalizationAlgorithm,
1053    /// Whether deterministic ordering is enabled
1054    pub deterministic_ordering: bool,
1055    /// Whether comments are preserved
1056    pub preserve_comments: bool,
1057    /// Whether processing instructions are preserved
1058    pub preserve_processing_instructions: bool,
1059    /// Namespace handling strategy
1060    pub namespace_handling: NamespaceHandling,
1061}
1062
1063/// Namespace handling strategies
1064#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1065pub enum NamespaceHandling {
1066    /// Preserve original namespace prefixes
1067    Preserve,
1068    /// Minimize namespace declarations
1069    Minimize,
1070    /// Normalize namespace prefixes
1071    Normalize,
1072}
1073
1074/// Version information for the builder
1075pub fn version_info() -> String {
1076    format!(
1077        "DDEX Builder v{} â€Ē DB-C14N/{} â€Ē Perfect Fidelity Engine â€Ē Rust {}",
1078        env!("CARGO_PKG_VERSION"),
1079        DB_C14N_VERSION,
1080        env!("CARGO_PKG_RUST_VERSION", "unknown")
1081    )
1082}
1083
1084/// Get Perfect Fidelity Engine information
1085pub fn fidelity_engine_info() -> String {
1086    format!(
1087        "Perfect Fidelity Engine v{} â€Ē Round-trip: ✓ â€Ē DB-C14N/{} â€Ē Extensions: ✓",
1088        env!("CARGO_PKG_VERSION"),
1089        DB_C14N_VERSION
1090    )
1091}
1092
1093#[cfg(test)]
1094mod tests {
1095    use super::*;
1096    
1097    #[test]
1098    fn test_builder_creation() {
1099        let builder = Builder::new();
1100        assert!(!builder.is_preset_locked());
1101    }
1102    
1103    #[test]
1104    fn test_preset_application() {
1105        let mut builder = Builder::new();
1106        assert!(builder.apply_preset("audio_album", false).is_ok());
1107        assert!(!builder.is_preset_locked());
1108        
1109        assert!(builder.apply_preset("audio_album", true).is_ok());
1110        assert!(builder.is_preset_locked());
1111    }
1112    
1113    #[test]
1114    fn test_unknown_preset() {
1115        let mut builder = Builder::new();
1116        assert!(builder.apply_preset("unknown_preset", false).is_err());
1117    }
1118    
1119    #[test]
1120    fn test_version_info() {
1121        let info = version_info();
1122        assert!(info.contains("DDEX Builder"));
1123        assert!(info.contains("DB-C14N/1.0"));
1124    }
1125}