yerba 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9b0696495b8437f9deea398cba7c4e6af00a8983ffa0cb519492aca22426ba46
4
- data.tar.gz: 42daabe671e951b350286a5ec6a63690466aff8f8b8828ebd8e570e8fc8758d3
3
+ metadata.gz: c659373d09accba735b75efdae48ee3c22a801f95f9669403bbc96220c29e80b
4
+ data.tar.gz: 28625aeb5c6939da11d4dfc9fd6de3d17e5f7923c4c49d2bfcb97b5dcf9ba9f0
5
5
  SHA512:
6
- metadata.gz: 2e245101d150f74c63f49a8caaa7e78f7966f25934ee6678a42629b4633758d6f74e3e638892dd4972ec11f0f2c734f93df85debebe809abcbaad19ca67380f5
7
- data.tar.gz: 289f195705e6d427bb6f263b8dc826b1107923cdd7022594d2806e47906f6acac3011ae9fb40802e6313bda281d66662168a93c525d5868e14e9435a99758f8b
6
+ metadata.gz: ade24547cfc1b6b9423dac87eef5a979c10aa5a1d0755912273d9504d928587447d876e693beba7ab6bc5ab7185c534ebd956e3cf7172ef3d308b8a112dfb3ec
7
+ data.tar.gz: 898d28671752d146d0da2f695839af841b75462c3aec72192f277349778aec635df9c9775fb8015124dae6973011af1ce996115d3a9c7fa1303fb031c50217c1
data/lib/yerba/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Yerba
4
- VERSION = "0.7.0"
4
+ VERSION = "0.7.1"
5
5
  end
data/rust/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "yerba"
3
- version = "0.7.0"
3
+ version = "0.7.1"
4
4
  edition = "2021"
5
5
  authors = ["Marco Roth <marco.roth@intergga.ch>"]
6
6
  description = "YAML Editing and Refactoring with Better Accuracy"
@@ -406,42 +406,120 @@ impl Document {
406
406
  }
407
407
 
408
408
  loop {
409
- let value = match self.get_value(scope_path) {
410
- Some(value) => value,
411
- None => return Ok(()),
409
+ let source = self.root.text().to_string();
410
+
411
+ let scope_node = if scope_path.is_empty() {
412
+ self.root.clone()
413
+ } else {
414
+ match self.navigate(scope_path) {
415
+ Ok(node) => node,
416
+ Err(_) => return Ok(()),
417
+ }
412
418
  };
413
419
 
414
- let mut selectors = Vec::new();
420
+ let mut mismatch_ranges: Vec<TextRange> = Vec::new();
421
+
422
+ for descendant in scope_node.descendants() {
423
+ if !BlockSeq::can_cast(descendant.kind()) {
424
+ continue;
425
+ }
426
+
427
+ let parent_entry = match descendant.ancestors().find(|ancestor| ancestor.kind() == SyntaxKind::BLOCK_MAP_ENTRY) {
428
+ Some(entry) => entry,
429
+ None => continue,
430
+ };
431
+
432
+ let first_entry = match BlockSeq::cast(descendant.clone()).and_then(|sequence| sequence.entries().next()) {
433
+ Some(entry) => entry,
434
+ None => continue,
435
+ };
436
+
437
+ let key_indent = preceding_whitespace_indent(&parent_entry).len();
438
+ let entry_indent = preceding_whitespace_indent(first_entry.syntax()).len();
439
+ let is_indented = entry_indent > key_indent;
415
440
 
416
- if !scope_path.is_empty() {
417
- selectors.push(scope_path.to_string());
441
+ if (style == "indented" && !is_indented) || (style == "compact" && is_indented) {
442
+ mismatch_ranges.push(descendant.text_range());
443
+ }
418
444
  }
419
445
 
420
- collect_selectors(&value, scope_path, &mut selectors);
446
+ if mismatch_ranges.is_empty() {
447
+ return Ok(());
448
+ }
421
449
 
422
- let concrete_selectors: Vec<String> = selectors
423
- .into_iter()
424
- .flat_map(|selector| {
425
- if selector.contains("[]") {
426
- self.resolve_selectors(&selector)
427
- } else {
428
- vec![selector]
429
- }
430
- })
431
- .collect();
450
+ let mut edits: Vec<(TextRange, String)> = Vec::new();
432
451
 
433
- let mut sequence_selectors: Vec<String> = concrete_selectors
434
- .into_iter()
435
- .filter(|selector| self.get_sequence_indent(selector).is_some_and(|current_style| current_style != style))
436
- .collect();
452
+ for range in &mismatch_ranges {
453
+ if mismatch_ranges.iter().any(|other| other != range && range.contains_range(*other)) {
454
+ continue;
455
+ }
437
456
 
438
- if sequence_selectors.is_empty() {
457
+ let node = match scope_node
458
+ .descendants()
459
+ .find(|descendant| BlockSeq::can_cast(descendant.kind()) && descendant.text_range() == *range)
460
+ {
461
+ Some(node) => node,
462
+ None => continue,
463
+ };
464
+ let parent_entry = match node.ancestors().find(|ancestor| ancestor.kind() == SyntaxKind::BLOCK_MAP_ENTRY) {
465
+ Some(entry) => entry,
466
+ None => continue,
467
+ };
468
+ let first_entry = match BlockSeq::cast(node).and_then(|seq| seq.entries().next()) {
469
+ Some(entry) => entry,
470
+ None => continue,
471
+ };
472
+
473
+ let key_indent = preceding_whitespace_indent(&parent_entry).len();
474
+ let entry_indent = preceding_whitespace_indent(first_entry.syntax()).len();
475
+
476
+ let indent_diff: i32 = match style {
477
+ "indented" => (key_indent as i32 + 2) - entry_indent as i32,
478
+ "compact" => key_indent as i32 - entry_indent as i32,
479
+ _ => continue,
480
+ };
481
+
482
+ if indent_diff == 0 {
483
+ continue;
484
+ }
485
+
486
+ let seq_start: usize = range.start().into();
487
+ let line_start = source[..seq_start].rfind('\n').map(|pos| pos + 1).unwrap_or(0);
488
+ let full_text = &source[line_start..usize::from(range.end())];
489
+
490
+ let reindented: String = full_text
491
+ .lines()
492
+ .map(|line| {
493
+ if line.trim().is_empty() {
494
+ String::new()
495
+ } else {
496
+ let current_indent = line.len() - line.trim_start().len();
497
+ let new_indent = (current_indent as i32 + indent_diff).max(0) as usize;
498
+ format!("{}{}", " ".repeat(new_indent), line.trim_start())
499
+ }
500
+ })
501
+ .collect::<Vec<_>>()
502
+ .join("\n");
503
+
504
+ edits.push((TextRange::new(rowan::TextSize::from(line_start as u32), range.end()), reindented));
505
+ }
506
+
507
+ if edits.is_empty() {
439
508
  return Ok(());
440
509
  }
441
510
 
442
- sequence_selectors.sort_by_key(|selector| std::cmp::Reverse(selector.len()));
511
+ edits.sort_by_key(|edit| std::cmp::Reverse(edit.0.start()));
512
+
513
+ let mut new_source = source;
514
+ for (range, replacement) in edits {
515
+ let start: usize = range.start().into();
516
+ let end: usize = range.end().into();
517
+ new_source.replace_range(start..end, &replacement);
518
+ }
443
519
 
444
- self.set_sequence_indent(&sequence_selectors[0], style)?;
520
+ let path = self.path.take();
521
+ *self = Self::parse(&new_source)?;
522
+ self.path = path;
445
523
  }
446
524
  }
447
525
 
@@ -439,6 +439,24 @@ impl Yerbafile {
439
439
  results
440
440
  }
441
441
 
442
+ fn relativize_path(&self, file_path: &str) -> Option<String> {
443
+ let path = Path::new(file_path);
444
+
445
+ if !path.is_absolute() {
446
+ return None;
447
+ }
448
+
449
+ if let Some(directory) = &self.directory {
450
+ if let Ok(relative) = path.strip_prefix(directory) {
451
+ return Some(relative.to_string_lossy().to_string());
452
+ }
453
+ }
454
+
455
+ std::env::current_dir()
456
+ .ok()
457
+ .and_then(|cwd| path.strip_prefix(&cwd).ok().map(|relative| relative.to_string_lossy().to_string()))
458
+ }
459
+
442
460
  fn should_run_global_pipeline(&self, file_path: &str) -> bool {
443
461
  if self.pipeline.is_empty() {
444
462
  return false;
@@ -454,15 +472,17 @@ impl Yerbafile {
454
472
 
455
473
  pub fn apply_to_document(&self, document: &mut Document, file_path: &str) -> Result<bool, YerbaError> {
456
474
  let original = document.to_string();
475
+ let relative_path = self.relativize_path(file_path);
476
+ let match_path = relative_path.as_deref().unwrap_or(file_path);
457
477
 
458
- if self.should_run_global_pipeline(file_path) {
478
+ if self.should_run_global_pipeline(match_path) {
459
479
  execute_pipeline(document, &self.pipeline, None, file_path, self)?;
460
480
  }
461
481
 
462
482
  for rule in &self.rules {
463
- if !file_path.is_empty() {
483
+ if !match_path.is_empty() {
464
484
  if let Ok(pattern) = glob::Pattern::new(&rule.files) {
465
- if !pattern.matches(file_path) && !pattern.matches_path(Path::new(file_path)) {
485
+ if !pattern.matches(match_path) && !pattern.matches_path(Path::new(match_path)) {
466
486
  continue;
467
487
  }
468
488
  } else {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yerba
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marco Roth