oak_core/source/buffer.rs
1//! Source buffer for code generation and minification.
2
3/// A trait for types that can be converted to source code.
4pub trait ToSource {
5 /// Writes the source code representation of this type to the provided buffer.
6 fn to_source(&self, buffer: &mut SourceBuffer);
7
8 /// Converts this type to a source code string.
9 fn to_source_string(&self) -> String {
10 let mut buffer = SourceBuffer::new();
11 self.to_source(&mut buffer);
12 buffer.finish()
13 }
14}
15
16/// A buffer for building source code with intelligent spacing for minification.
17#[derive(Debug, Clone, Default)]
18pub struct SourceBuffer {
19 inner: String,
20 last_char: Option<char>,
21}
22
23impl SourceBuffer {
24 /// Creates a new, empty source buffer.
25 pub fn new() -> Self {
26 Self::default()
27 }
28
29 /// Pushes a string to the buffer, automatically adding a space if necessary to prevent token merging.
30 pub fn push(&mut self, s: &str) {
31 if let Some(first) = s.chars().next() {
32 // If both the last character and the first character of the new string are "word" characters,
33 // we must insert a space to prevent them from merging into a single token (e.g., "let" + "a" -> "let a").
34 if self.is_word_char(self.last_char) && self.is_word_char(Some(first)) {
35 self.inner.push(' ');
36 }
37 self.inner.push_str(s);
38 self.last_char = s.chars().last();
39 }
40 }
41
42 /// Returns the accumulated source code as a string.
43 pub fn finish(self) -> String {
44 self.inner
45 }
46
47 /// Helper to check if a character is a "word" character (alphanumeric or underscore).
48 fn is_word_char(&self, c: Option<char>) -> bool {
49 c.map_or(false, |c| c.is_alphanumeric() || c == '_')
50 }
51}
52
53impl From<SourceBuffer> for String {
54 fn from(buffer: SourceBuffer) -> Self {
55 buffer.finish()
56 }
57}