1mod prettify;
2#[cfg(feature = "serde")]
3pub mod serde;
4pub(crate) mod uglify;
5
6pub use prettify::{prettify_document, prettify_document_into, prettify_str};
7pub use uglify::{uglify_document, uglify_document_into, uglify_str, uglify_str_into};
8
9use crate::ast::Document;
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum FormatRequest {
13 Json(JsonMode),
14 Jsonlines(JsonlinesOptions),
15}
16
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub enum JsonMode {
19 Prettify(PrettifyOptions),
20 Uglify,
21}
22
23impl Default for FormatRequest {
24 fn default() -> Self {
25 Self::Json(JsonMode::default())
26 }
27}
28
29impl Default for JsonMode {
30 fn default() -> Self {
31 Self::Prettify(PrettifyOptions::default())
32 }
33}
34
35#[derive(bon::Builder, Debug, Clone, PartialEq, Eq)]
36pub struct PrettifyOptions {
37 #[builder(default = 80)]
38 pub preferred_width: usize,
39 #[builder(default)]
40 pub line_ending: LineEnding,
41}
42
43impl Default for PrettifyOptions {
44 fn default() -> Self {
45 Self::builder().build()
46 }
47}
48
49#[derive(bon::Builder, Default, Debug, Clone, PartialEq, Eq)]
50pub struct JsonlinesOptions {
51 #[builder(default)]
52 pub line_ending: LineEnding,
53}
54
55pub fn format_document<S: AsRef<str>>(doc: &Document<S>, mode: &JsonMode) -> String {
56 match mode {
57 JsonMode::Prettify(opts) => prettify_document(doc, opts.preferred_width, opts.line_ending),
58 JsonMode::Uglify => uglify_document(doc),
59 }
60}
61
62use crate::tokens::{FALSE, NULL, TRUE};
63
64pub(crate) fn join_into<T, B>(
65 buf: &mut B,
66 items: impl IntoIterator<Item = T>,
67 mut item_fmt: impl FnMut(&mut B, &T),
68 mut delim_fmt: impl FnMut(&mut B, &T),
69) {
70 let mut iter = items.into_iter();
71 if let Some(first) = iter.next() {
72 item_fmt(buf, &first);
73 for item in iter {
74 delim_fmt(buf, &item);
75 item_fmt(buf, &item);
76 }
77 }
78}
79
80#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
81pub enum LineEnding {
82 #[default]
83 Lf,
84 CrLf,
85}
86
87impl LineEnding {
88 pub const fn as_str(self) -> &'static str {
89 match self {
90 Self::Lf => "\n",
91 Self::CrLf => "\r\n",
92 }
93 }
94}
95
96pub(crate) trait Emitter {
97 fn push(&mut self, c: char);
98 fn push_str(&mut self, s: &str);
99
100 fn push_quoted(&mut self, s: &str) {
102 self.push('"');
103 self.push_str(s);
104 self.push('"');
105 }
106
107 fn emit_null(&mut self) {
108 self.push_str(NULL);
109 }
110 fn emit_string(&mut self, s: &str) {
111 self.push_quoted(s);
112 }
113 fn emit_mantissa(&mut self, n: &str) {
114 self.push_str(n);
115 }
116 fn emit_exponent(&mut self, e: &str) {
117 self.push('e');
118 self.push_str(e);
119 }
120 fn emit_boolean(&mut self, b: bool) {
121 self.push_str(if b { TRUE } else { FALSE });
122 }
123 fn emit_item_delim(&mut self) {
124 self.push(',');
125 }
126 fn emit_array_open(&mut self) {
127 self.push('[');
128 }
129 fn emit_array_close(&mut self) {
130 self.push(']');
131 }
132 fn emit_object_open(&mut self) {
133 self.push('{');
134 }
135 fn emit_object_close(&mut self) {
136 self.push('}');
137 }
138 fn emit_key_val_delim(&mut self) {
139 self.push(':');
140 }
141}