1#![deny(missing_docs)]
6use {
7 crate::{content::*, error::*, options::*},
8 std::cell::RefCell,
9 std::collections::HashMap,
10 std::collections::HashSet,
11 std::rc::Rc,
12};
13
14pub(crate) struct SubpathOptions {
15 subpath_options_by_name: HashMap<String, Rc<RefCell<SubpathOptions>>>,
18
19 unnamed_subpath_options: Option<Rc<RefCell<SubpathOptions>>>,
22
23 pub options: FormatOptions,
26
27 property_name_priorities: HashMap<&'static str, usize>,
29}
30
31impl SubpathOptions {
32 const NO_PRIORITY: usize = std::usize::MAX;
35
36 pub fn new(default_options: &FormatOptions) -> Self {
37 Self {
38 subpath_options_by_name: HashMap::new(),
39 unnamed_subpath_options: None,
40 options: default_options.clone(),
41 property_name_priorities: HashMap::new(),
42 }
43 }
44
45 pub fn override_default_options(&mut self, path_options: &HashSet<PathOption>) {
46 for path_option in path_options.iter() {
47 use PathOption::*;
48 match path_option {
49 TrailingCommas(path_value) => self.options.trailing_commas = *path_value,
50 CollapseContainersOfOne(path_value) => {
51 self.options.collapse_containers_of_one = *path_value
52 }
53 SortArrayItems(path_value) => self.options.sort_array_items = *path_value,
54 PropertyNameOrder(property_names) => {
55 for (index, property_name) in property_names.iter().enumerate() {
56 self.property_name_priorities.insert(property_name, index);
57 }
58 }
59 }
60 }
61 }
62
63 pub fn get_or_create_subpath_options(
64 &mut self,
65 path: &[&str],
66 default_options: &FormatOptions,
67 ) -> Rc<RefCell<SubpathOptions>> {
68 let name_or_star = path[0];
69 let remaining_path = &path[1..];
70 let subpath_options_ref = if name_or_star == "*" {
71 self.unnamed_subpath_options.as_ref()
72 } else {
73 self.subpath_options_by_name.get(name_or_star)
74 };
75 let subpath_options = match subpath_options_ref {
76 Some(existing_options) => existing_options.clone(),
77 None => {
78 let new_options = Rc::new(RefCell::new(SubpathOptions::new(default_options)));
79 if name_or_star == "*" {
80 self.unnamed_subpath_options = Some(new_options.clone());
81 } else {
82 self.subpath_options_by_name
83 .insert(name_or_star.to_string(), new_options.clone());
84 }
85 new_options
86 }
87 };
88 if remaining_path.len() == 0 {
89 subpath_options
90 } else {
91 (*subpath_options.borrow_mut())
92 .get_or_create_subpath_options(remaining_path, default_options)
93 }
94 }
95
96 fn get_subpath_options(&self, path: &[&str]) -> Option<Rc<RefCell<SubpathOptions>>> {
97 let name_or_star = path[0];
98 let remaining_path = &path[1..];
99 let subpath_options_ref = if name_or_star == "*" {
100 self.unnamed_subpath_options.as_ref()
101 } else {
102 self.subpath_options_by_name.get(name_or_star)
103 };
104 if let Some(subpath_options) = subpath_options_ref {
105 if remaining_path.len() == 0 {
106 Some(subpath_options.clone())
107 } else {
108 (*subpath_options.borrow()).get_subpath_options(remaining_path)
109 }
110 } else {
111 None
112 }
113 }
114
115 fn get_options_for(&self, name_or_star: &str) -> Option<Rc<RefCell<SubpathOptions>>> {
116 self.get_subpath_options(&[name_or_star])
117 }
118
119 pub fn get_property_priority(&self, property_name: &str) -> usize {
120 match self.property_name_priorities.get(property_name) {
121 Some(priority) => *priority,
122 None => SubpathOptions::NO_PRIORITY,
123 }
124 }
125
126 fn debug_format(
127 &self,
128 formatter: &mut std::fmt::Formatter<'_>,
129 indent: &str,
130 ) -> std::fmt::Result {
131 writeln!(formatter, "{{")?;
132 let next_indent = indent.to_owned() + " ";
133 writeln!(formatter, "{}options = {:?}", &next_indent, self.options)?;
134 writeln!(
135 formatter,
136 "{}property_name_priorities = {:?}",
137 &next_indent, self.property_name_priorities
138 )?;
139 if let Some(unnamed_subpath_options) = &self.unnamed_subpath_options {
140 write!(formatter, "{}* = ", &next_indent)?;
141 (*unnamed_subpath_options.borrow()).debug_format(formatter, &next_indent)?;
142 writeln!(formatter)?;
143 }
144 for (property_name, subpath_options) in self.subpath_options_by_name.iter() {
145 write!(formatter, "{}{} = ", &next_indent, property_name)?;
146 (*subpath_options.borrow()).debug_format(formatter, &next_indent)?;
147 writeln!(formatter)?;
148 }
149 writeln!(formatter, "{}}}", &indent)
150 }
151}
152
153impl std::fmt::Debug for SubpathOptions {
154 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155 self.debug_format(formatter, "")
156 }
157}
158
159pub(crate) struct Formatter {
161 depth: usize,
165
166 pending_indent: bool,
168
169 bytes: Vec<u8>,
171
172 column: usize,
174
175 subpath_options_stack: Vec<Option<Rc<RefCell<SubpathOptions>>>>,
179
180 default_options: FormatOptions,
185}
186
187impl Formatter {
188 pub fn new(
191 default_options: FormatOptions,
192 document_root_options_ref: Rc<RefCell<SubpathOptions>>,
193 ) -> Self {
194 Formatter {
195 depth: 0,
196 pending_indent: false,
197 bytes: vec![],
198 column: 1,
199 subpath_options_stack: vec![Some(document_root_options_ref)],
200 default_options,
201 }
202 }
203
204 pub fn increase_indent(&mut self) -> Result<&mut Formatter, Error> {
205 self.depth += 1;
206 Ok(self)
207 }
208
209 pub fn decrease_indent(&mut self) -> Result<&mut Formatter, Error> {
210 self.depth -= 1;
211 Ok(self)
212 }
213
214 pub fn append(&mut self, content: &str) -> Result<&mut Formatter, Error> {
216 if self.pending_indent && !content.starts_with("\n") {
217 let spaces = self.depth * self.default_options.indent_by;
218 self.bytes.extend_from_slice(" ".repeat(spaces).as_bytes());
219 self.column = spaces + 1;
220 self.pending_indent = false;
221 }
222 if content.ends_with("\n") {
223 self.column = 1;
224 self.bytes.extend_from_slice(content.as_bytes());
225 } else {
226 let mut first = true;
227 for line in content.lines() {
228 if !first {
229 self.bytes.extend_from_slice("\n".as_bytes());
230 self.column = 1;
231 }
232 self.bytes.extend_from_slice(line.as_bytes());
233 self.column += line.len();
234 first = false;
235 }
236 }
237 Ok(self)
238 }
239
240 pub fn append_newline(&mut self) -> Result<&mut Formatter, Error> {
241 self.append("\n")
242 }
243
244 pub fn start_next_line(&mut self) -> Result<&mut Formatter, Error> {
247 if self.bytes.len() > 0 {
248 self.append_newline()?;
249 }
250 self.pending_indent = true;
251 Ok(self)
252 }
253
254 fn format_content<F>(&mut self, content_fn: F) -> Result<&mut Formatter, Error>
255 where
256 F: FnOnce(&mut Formatter) -> Result<&mut Formatter, Error>,
257 {
258 content_fn(self)
259 }
260
261 pub fn format_container<F>(
262 &mut self,
263 left_brace: &str,
264 right_brace: &str,
265 content_fn: F,
266 ) -> Result<&mut Formatter, Error>
267 where
268 F: FnOnce(&mut Formatter) -> Result<&mut Formatter, Error>,
269 {
270 self.append(left_brace)?
271 .increase_indent()?
272 .format_content(content_fn)?
273 .decrease_indent()?
274 .append(right_brace)
275 }
276
277 fn format_comments_internal(
278 &mut self,
279 comments: &Vec<Comment>,
280 leading_blank_line: bool,
281 ) -> Result<&mut Formatter, Error> {
282 let mut previous: Option<&Comment> = None;
283 for comment in comments.iter() {
284 match previous {
285 Some(previous) => {
286 if comment.is_block() || previous.is_block() {
287 self.append_newline()?;
291 }
292 }
293 None => {
294 if leading_blank_line {
295 self.start_next_line()?;
296 }
297 }
298 }
299 comment.format(self)?;
300 previous = Some(comment)
301 }
302 Ok(self)
303 }
304
305 pub fn format_comments(
306 &mut self,
307 comments: &Vec<Comment>,
308 is_first: bool,
309 ) -> Result<&mut Formatter, Error> {
310 self.format_comments_internal(comments, !is_first)
311 }
312
313 pub fn format_trailing_comments(
314 &mut self,
315 comments: &Vec<Comment>,
316 ) -> Result<&mut Formatter, Error> {
317 self.format_comments_internal(comments, true)
318 }
319
320 pub fn get_current_subpath_options(&self) -> Option<&Rc<RefCell<SubpathOptions>>> {
321 self.subpath_options_stack.last().unwrap().as_ref()
322 }
323
324 fn enter_scope(&mut self, name_or_star: &str) {
325 let mut subpath_options_to_push = None;
326 if let Some(current_subpath_options_ref) = self.get_current_subpath_options() {
327 let current_subpath_options = &*current_subpath_options_ref.borrow();
328 if let Some(next_subpath_options_ref) =
329 current_subpath_options.get_options_for(name_or_star)
330 {
331 subpath_options_to_push = Some(next_subpath_options_ref.clone());
335 } else if name_or_star != "*" {
336 if let Some(next_subpath_options_ref) = current_subpath_options.get_options_for("*")
337 {
338 subpath_options_to_push = Some(next_subpath_options_ref.clone());
343 }
344 }
345 }
346 self.subpath_options_stack.push(subpath_options_to_push);
347 }
348
349 fn exit_scope(&mut self) {
350 self.subpath_options_stack.pop();
351 }
352
353 fn format_scoped_value(
354 &mut self,
355 name: Option<&str>,
356 value: &mut Value,
357 is_first: bool,
358 is_last: bool,
359 container_has_pending_comments: bool,
360 ) -> Result<&mut Formatter, Error> {
361 let collapsed = is_first
362 && is_last
363 && value.is_primitive()
364 && !value.has_comments()
365 && !container_has_pending_comments
366 && self.options_in_scope().collapse_containers_of_one;
367 match name {
368 Some(name) => self.enter_scope(name),
372 None => self.enter_scope("*"),
373 }
374 if collapsed {
375 self.append(" ")?;
376 } else {
377 if is_first {
378 self.start_next_line()?;
379 }
380 self.format_comments(&value.comments().before_value(), is_first)?;
381 }
382 if let Some(name) = name {
383 self.append(&format!("{}: ", name))?;
384 }
385 value.format(self)?;
386 self.exit_scope();
387 if collapsed {
391 self.append(" ")?;
392 } else {
393 self.append_comma(is_last)?
394 .append_end_of_line_comment(value.comments().end_of_line())?
395 .start_next_line()?;
396 }
397 Ok(self)
398 }
399
400 pub fn format_item(
401 &mut self,
402 item: &Rc<RefCell<Value>>,
403 is_first: bool,
404 is_last: bool,
405 container_has_pending_comments: bool,
406 ) -> Result<&mut Formatter, Error> {
407 self.format_scoped_value(
408 None,
409 &mut *item.borrow_mut(),
410 is_first,
411 is_last,
412 container_has_pending_comments,
413 )
414 }
415
416 pub fn format_property(
417 &mut self,
418 property: &Property,
419 is_first: bool,
420 is_last: bool,
421 container_has_pending_comments: bool,
422 ) -> Result<&mut Formatter, Error> {
423 self.format_scoped_value(
424 Some(&property.name),
425 &mut *property.value.borrow_mut(),
426 is_first,
427 is_last,
428 container_has_pending_comments,
429 )
430 }
431
432 pub fn options_in_scope(&self) -> FormatOptions {
433 match self.get_current_subpath_options() {
434 Some(subpath_options) => (*subpath_options.borrow()).options.clone(),
435 None => self.default_options.clone(),
436 }
437 }
438
439 fn append_comma(&mut self, is_last: bool) -> Result<&mut Formatter, Error> {
440 if !is_last || self.options_in_scope().trailing_commas {
441 self.append(",")?;
442 }
443 Ok(self)
444 }
445
446 fn append_end_of_line_comment(
450 &mut self,
451 comment: &Option<String>,
452 ) -> Result<&mut Formatter, Error> {
453 if let Some(comment) = comment {
454 let start_column = self.column;
455 let mut first = true;
456 for line in comment.lines() {
457 if !first {
458 self.append_newline()?;
459 self.append(&" ".repeat(start_column - 1))?;
460 }
461 self.append(&format!(" //{}", line))?;
462 first = false;
463 }
464 }
465 Ok(self)
466 }
467
468 pub fn format(mut self, parsed_document: &ParsedDocument) -> Result<Vec<u8>, Error> {
470 parsed_document.content.format_content(&mut self)?;
471 Ok(self.bytes)
472 }
473}