yerba 0.7.5 → 0.7.6

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: d03e5cb5c88654843c8c86735f91d1e550e81282ccd1c0db8813527c4b4f9898
4
- data.tar.gz: 805516b5ce364c09dab736e562f4a09d312d70b75ceb2c9e22a9e63fad45eb6d
3
+ metadata.gz: c8388badb1c673c2f6815631a955f731b1699ed4f6aea305a73519e2f231d63c
4
+ data.tar.gz: dc153bff8304870d85e4631e794d04a4ec107d93fc8a7b8738845e2b3ead7133
5
5
  SHA512:
6
- metadata.gz: 9cb2ace3f935a023bdd938cde43010f158efc18fce052a7fe5780cf3f9362779d0bc66a463f60453586b24e0b2e6b2ed180cf7d71d2f99095b57d0eb2adc92d8
7
- data.tar.gz: a4946b677d5b05d2741a09749e540056376dc2d2724f12bc383d722974638576bfdf022a9a02587c75b4167d9d9ae644ddcb45ed6d3f86167423c8d7263c7ba3
6
+ metadata.gz: be8d6ee312803ab9fca14e5d3a692fcc601354144918d5e7ef9237348ec8a51be42ffec4cef0bef9a5a680477c8344578118b29f094dd9202944292db54683fd
7
+ data.tar.gz: 77f14d190d24bfbabc069a8ba015c813ff525564cc5c18767d9a6806f546526bd53555eeabff25e64da2bbbd6dc08a82f72b8443e75ac61250c0751bcc8755c7
data/README.md CHANGED
@@ -539,6 +539,7 @@ Available pipeline steps:
539
539
  - `directives` Add or remove the document start marker (`---`), with optional `max` validation
540
540
  - `unique` Find or remove duplicate items in a sequence
541
541
  - `schema` Validate against a JSON schema (with optional `path` for scoping)
542
+ - `final_newline` Enforce exact number of trailing newlines (`count: 1` by default, strips extras)
542
543
 
543
544
  This makes it easy to enforce project-wide YAML conventions in CI:
544
545
 
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.5"
4
+ VERSION = "0.7.6"
5
5
  end
data/rust/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "yerba"
3
- version = "0.7.5"
3
+ version = "0.7.6"
4
4
  edition = "2021"
5
5
  authors = ["Marco Roth <marco.roth@intergga.ch>"]
6
6
  description = "YAML Editing and Refactoring with Better Accuracy"
@@ -656,6 +656,18 @@ impl Document {
656
656
  self.reparse(&new_source)
657
657
  }
658
658
 
659
+ pub fn enforce_final_newline(&mut self, count: usize) -> Result<(), YerbaError> {
660
+ let source = self.to_string();
661
+ let trimmed = source.trim_end_matches('\n');
662
+ let expected = format!("{}{}", trimmed, "\n".repeat(count));
663
+
664
+ if source != expected {
665
+ self.reparse(&expected)
666
+ } else {
667
+ Ok(())
668
+ }
669
+ }
670
+
659
671
  pub fn enforce_key_style(&mut self, style: &crate::KeyStyle, dot_path: Option<&str>) -> Result<(), YerbaError> {
660
672
  let scope_ranges: Vec<TextRange> = match dot_path {
661
673
  Some(path) if !path.is_empty() => self.navigate_all_compact(path).iter().map(|node| node.text_range()).collect(),
@@ -41,6 +41,7 @@ pub enum PipelineStep {
41
41
  Directives(DirectivesConfig),
42
42
  Unique(UniqueConfig),
43
43
  Schema(SchemaConfig),
44
+ FinalNewline(FinalNewlineConfig),
44
45
  }
45
46
 
46
47
  #[derive(Debug, Clone, Deserialize)]
@@ -95,6 +96,16 @@ pub struct SchemaConfig {
95
96
  pub items: bool,
96
97
  }
97
98
 
99
+ #[derive(Debug, Clone, Deserialize)]
100
+ pub struct FinalNewlineConfig {
101
+ #[serde(default = "default_one")]
102
+ pub count: usize,
103
+ }
104
+
105
+ fn default_one() -> usize {
106
+ 1
107
+ }
108
+
98
109
  #[derive(Debug, Clone, Deserialize)]
99
110
  pub struct RenameConfig {
100
111
  pub from: String,
@@ -188,8 +199,13 @@ impl<'de> Deserialize<'de> for PipelineStep {
188
199
  return Ok(PipelineStep::Schema(config));
189
200
  }
190
201
 
202
+ if let Some(value) = mapping.get(yaml_serde::Value::String("final_newline".to_string())) {
203
+ let config: FinalNewlineConfig = yaml_serde::from_value(value.clone()).map_err(serde::de::Error::custom)?;
204
+ return Ok(PipelineStep::FinalNewline(config));
205
+ }
206
+
191
207
  Err(serde::de::Error::custom(
192
- "unknown pipeline step: expected sort_keys, quote_style, collection_style, sequence_indent, set, insert, delete, rename, remove, blank_lines, sort, directives, unique, or schema",
208
+ "unknown pipeline step: expected sort_keys, quote_style, collection_style, sequence_indent, set, insert, delete, rename, remove, blank_lines, sort, directives, unique, schema, or final_newline",
193
209
  ))
194
210
  }
195
211
  }
@@ -359,6 +375,22 @@ impl Yerbafile {
359
375
  results.extend(file_results);
360
376
  }
361
377
 
378
+ if !self.pipeline.is_empty() {
379
+ if let Some(ref global_glob) = self.files {
380
+ if let Ok(paths) = glob::glob(global_glob) {
381
+ let unprocessed: Vec<String> = paths
382
+ .filter_map(|entry| entry.ok())
383
+ .map(|path| path.to_string_lossy().to_string())
384
+ .filter(|file| !globally_processed.contains(file.as_str()))
385
+ .collect();
386
+
387
+ let global_results: Vec<RuleResult> = unprocessed.par_iter().map(|file| self.apply_global_pipeline_to_file(file, write)).collect();
388
+
389
+ results.extend(global_results);
390
+ }
391
+ }
392
+ }
393
+
362
394
  results
363
395
  }
364
396
 
@@ -436,9 +468,55 @@ impl Yerbafile {
436
468
  ran_global = true;
437
469
  }
438
470
 
471
+ if !ran_global && self.should_run_global_pipeline(file) {
472
+ results.push(self.apply_global_pipeline_to_file(file, write));
473
+ }
474
+
439
475
  results
440
476
  }
441
477
 
478
+ fn apply_global_pipeline_to_file(&self, file: &str, write: bool) -> RuleResult {
479
+ let mut document = match Document::parse_file(file) {
480
+ Ok(document) => document,
481
+ Err(error) => {
482
+ return RuleResult {
483
+ file: file.to_string(),
484
+ changed: false,
485
+ error: Some(error),
486
+ }
487
+ }
488
+ };
489
+
490
+ let original = document.to_string();
491
+
492
+ if let Err(error) = execute_pipeline(&mut document, &self.pipeline, None, file, self) {
493
+ return RuleResult {
494
+ file: file.to_string(),
495
+ changed: false,
496
+ error: Some(error),
497
+ };
498
+ }
499
+
500
+ let new_content = document.to_string();
501
+ let changed = new_content != original;
502
+
503
+ if changed && write {
504
+ if let Err(error) = fs::write(file, &new_content) {
505
+ return RuleResult {
506
+ file: file.to_string(),
507
+ changed,
508
+ error: Some(YerbaError::IoError(error)),
509
+ };
510
+ }
511
+ }
512
+
513
+ RuleResult {
514
+ file: file.to_string(),
515
+ changed,
516
+ error: None,
517
+ }
518
+ }
519
+
442
520
  fn relativize_path(&self, file_path: &str) -> Option<String> {
443
521
  let path = Path::new(file_path);
444
522
 
@@ -744,6 +822,8 @@ fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<
744
822
 
745
823
  Ok(())
746
824
  }
825
+
826
+ PipelineStep::FinalNewline(config) => document.enforce_final_newline(config.count),
747
827
  }
748
828
  }
749
829
 
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.5
4
+ version: 0.7.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marco Roth