aboutsummaryrefslogtreecommitdiff
path: root/src/z/parser/js/formatter.zig
blob: fbea7bcbe429a71198e124c712710149a46b7be8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
const std = @import("std");

pub const FormatOptions = struct {
    indent_size: usize = 4,
    minify: bool = false,
};

pub const Formatter = struct {
    buf: []u8,
    pos: usize,
    indent_level: usize,
    options: FormatOptions,
    last_char: u8 = 0,

    pub fn write(self: *@This(), s: []const u8) void {
        if (self.options.minify) {
            if (s.len == 0) return;
            var start: usize = 0;
            while (start < s.len and s[start] == ' ') start += 1;
            var end = s.len;
            while (end > start and s[end - 1] == ' ') end -= 1;
            if (start >= end) return;
            const trimmed = s[start..end];
            if (self.last_char != 0 and isWordChar(self.last_char) and isWordChar(trimmed[0])) {
                self.buf[self.pos] = ' ';
                self.pos += 1;
            }
            @memcpy(self.buf[self.pos..][0..trimmed.len], trimmed);
            self.pos += trimmed.len;
            self.last_char = trimmed[trimmed.len - 1];
        } else {
            @memcpy(self.buf[self.pos..][0..s.len], s);
            self.pos += s.len;
        }
    }

    pub fn writeChar(self: *@This(), c: u8) void {
        self.buf[self.pos] = c;
        self.pos += 1;
        self.last_char = c;
    }

    pub fn writeIndent(self: *@This()) void {
        if (self.options.minify) return;
        const spaces = self.indent_level * self.options.indent_size;
        var i: usize = 0;
        while (i < spaces) : (i += 1) {
            self.writeChar(' ');
        }
    }

    pub fn newline(self: *@This()) void {
        if (self.options.minify) return;
        self.writeChar('\n');
    }

    pub fn writeSpace(self: *@This()) void {
        if (!self.options.minify) self.writeChar(' ');
    }

    fn isWordChar(c: u8) bool {
        return switch (c) {
            'a'...'z', 'A'...'Z', '0'...'9', '_', '$' => true,
            else => false,
        };
    }
};