Skip to main content

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