Skip to main content

Library/Fn/Transform/
private_field.rs

1//! Private field conversion transform
2//!
3//! Converts TypeScript private fields (#field) to regular properties (__field)
4//! for VSCode compatibility. VSCode does this for performance reasons.
5
6/// Configuration for the private field transform
7#[derive(Debug, Clone, Default)]
8pub struct Config {
9	/// Prefix to use for converted private fields
10	pub prefix:String,
11	/// Whether to preserve the original private identifier in comments
12	pub preserve_comments:bool,
13}
14
15impl Config {
16	pub fn new() -> Self { Self { prefix:"__".to_string(), preserve_comments:true } }
17}
18
19/// Transform that converts TypeScript private fields (#field) to regular
20/// properties
21///
22/// VSCode performs this conversion for performance reasons, as private fields
23/// using Symbol have more overhead than regular properties.
24///
25/// This module provides the configuration and interface. The actual transform
26/// is applied during compilation using the SWC visitor pattern.
27pub struct PrivateFieldTransform {
28	config:Config,
29}
30
31impl PrivateFieldTransform {
32	pub fn new() -> Self { Self { config:Config::new() } }
33
34	pub fn with_config(config:Config) -> Self { Self { config } }
35
36	/// Convert a private identifier to a regular identifier name
37	pub fn convert_private_name(&self, name:&str) -> String { format!("{}{}", self.config.prefix, name) }
38
39	/// Check if a name is a private field
40	pub fn is_private_field(&self, name:&str) -> bool { name.starts_with('#') }
41}
42
43impl Default for PrivateFieldTransform {
44	fn default() -> Self { Self::new() }
45}
46
47/// Apply the private field conversion to source code
48///
49/// This is a simple string-based replacement for basic cases.
50/// For complex cases, the SWC AST transform should be used.
51pub fn convert_private_fields(source:&str, prefix:&str) -> String {
52	let mut result = source.to_string();
53
54	// Simple pattern replacement for private field declarations
55	// This is a placeholder - full implementation would use AST
56	let patterns = [("#", prefix)];
57
58	for (old, new) in patterns {
59		if result.contains(old) && !result.contains(new) {
60			// Only replace if it looks like a private identifier
61			result = result.replace(&format!("{}.", old), &format!("{}.", new));
62		}
63	}
64
65	result
66}
67
68#[cfg(test)]
69mod tests {
70	use super::*;
71
72	#[test]
73	fn test_private_field_transform_creation() {
74		let transform = PrivateFieldTransform::new();
75		let config = transform.config;
76		assert_eq!(config.prefix, "__");
77	}
78
79	#[test]
80	fn test_private_field_transform_with_config() {
81		let config = Config { prefix:"_private_".to_string(), preserve_comments:false };
82		let transform = PrivateFieldTransform::with_config(config.clone());
83		assert_eq!(transform.config.prefix, "_private_");
84	}
85
86	#[test]
87	fn test_convert_private_name() {
88		let transform = PrivateFieldTransform::new();
89		assert_eq!(transform.convert_private_name("field"), "__field");
90	}
91
92	#[test]
93	fn test_is_private_field() {
94		let transform = PrivateFieldTransform::new();
95		assert!(transform.is_private_field("#field"));
96		assert!(!transform.is_private_field("field"));
97	}
98}