mirror of
https://github.com/zizmorcore/zizmor.git
synced 2025-12-23 08:47:33 +00:00
parent
ed0586a0b6
commit
1c5a36d1d5
3 changed files with 78 additions and 21 deletions
|
|
@ -579,12 +579,15 @@ impl Document {
|
|||
fn query_node(&self, query: &Query, mode: QueryMode) -> Result<Node, QueryError> {
|
||||
let mut focus_node = self.top_object()?;
|
||||
for component in &query.route {
|
||||
dbg!(&focus_node);
|
||||
match self.descend(&focus_node, component) {
|
||||
Ok(next) => focus_node = next,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
dbg!(&focus_node);
|
||||
|
||||
focus_node = match mode {
|
||||
QueryMode::Pretty => {
|
||||
// If we're in "pretty" mode, we want to return the
|
||||
|
|
@ -594,9 +597,8 @@ impl Document {
|
|||
//
|
||||
// NOTE: We might already be on the block/flow pair if we terminated
|
||||
// with an absent value, in which case we don't need to do this cleanup.
|
||||
if matches!(query.route.last(), Some(Component::Key(_)))
|
||||
&& focus_node.kind_id() != self.block_mapping_pair_id
|
||||
&& focus_node.kind_id() != self.flow_pair_id
|
||||
if focus_node.kind_id() != self.block_mapping_pair_id
|
||||
|| focus_node.kind_id() == self.flow_node_id
|
||||
{
|
||||
focus_node.parent().unwrap()
|
||||
} else {
|
||||
|
|
@ -650,6 +652,7 @@ impl Document {
|
|||
if matches!(mode, QueryMode::Pretty)
|
||||
&& matches!(query.route.last(), Some(Component::Key(_)))
|
||||
&& focus_node.kind_id() != self.block_mapping_pair_id
|
||||
&& focus_node.kind_id() != self.flow_pair_id
|
||||
{
|
||||
focus_node = focus_node.parent().unwrap()
|
||||
}
|
||||
|
|
@ -881,6 +884,24 @@ baz:
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_flow_pair_in_sequence() {
|
||||
let doc = r#"
|
||||
foo: [1, 2, 3: {abc: def}]
|
||||
"#;
|
||||
|
||||
let doc = Document::new(doc).unwrap();
|
||||
let query = Query {
|
||||
route: vec![Component::Key("foo"), Component::Index(2)],
|
||||
};
|
||||
|
||||
let feature = doc.query_pretty(&query).unwrap();
|
||||
assert_eq!(
|
||||
doc.extract_with_leading_whitespace(&feature),
|
||||
"3: {abc: def}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_feature_comments() {
|
||||
let doc = r#"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ testcase:
|
|||
|
||||
queries:
|
||||
- query: [flow1, foo]
|
||||
expected: "{ foo: [1, 2, 3: [4, 5, { a: b }]] }"
|
||||
expected: "foo: [1, 2, 3: [4, 5, { a: b }]]"
|
||||
|
||||
- query: [flow1, foo, 2]
|
||||
# TODO: ideally would be `3: [4, 5, { a: b }]`
|
||||
|
|
@ -28,7 +28,7 @@ queries:
|
|||
expected: "{ a: }"
|
||||
|
||||
- query: [flow4, foo]
|
||||
expected: "{\n foo: [1, 2, 3: [4, 5, { a: b }]],\n }"
|
||||
expected: " foo: [1, 2, 3: [4, 5, { a: b }]]"
|
||||
|
||||
- query: [flow5, 0]
|
||||
expected: " abc"
|
||||
|
|
@ -37,4 +37,4 @@ queries:
|
|||
expected: "def"
|
||||
|
||||
- query: [flow5, 2]
|
||||
expected: " xyz"
|
||||
expected: " xyz"
|
||||
|
|
|
|||
|
|
@ -168,7 +168,6 @@ pub enum Op<'doc> {
|
|||
updates: indexmap::IndexMap<String, serde_yaml::Value>,
|
||||
},
|
||||
/// Remove the key at the given path
|
||||
#[allow(dead_code)]
|
||||
Remove,
|
||||
}
|
||||
|
||||
|
|
@ -436,20 +435,16 @@ fn apply_single_patch(
|
|||
|
||||
let feature = route_to_feature_pretty(&patch.route, document)?;
|
||||
|
||||
// For removal, we need to remove the entire line including leading whitespace
|
||||
// TODO: This isn't sound, e.g. removing `b:` from `{a: a, b: b}` will
|
||||
// remove the entire line.
|
||||
let start_pos = {
|
||||
let range = line_span(document, feature.location.byte_span.0);
|
||||
range.start
|
||||
};
|
||||
let end_pos = {
|
||||
let range = line_span(document, feature.location.byte_span.1);
|
||||
range.end
|
||||
};
|
||||
|
||||
// At the moment, we simply delete the entire "pretty" feature.
|
||||
// This works well enough, but it will leave any leading
|
||||
// or trailing whitespace if not captured in the underlying
|
||||
// tree-sitter-extracted feature.
|
||||
let mut result = content.to_string();
|
||||
result.replace_range(start_pos..end_pos, "");
|
||||
result.replace_range(
|
||||
feature.location.byte_span.0..feature.location.byte_span.1,
|
||||
"",
|
||||
);
|
||||
|
||||
yamlpath::Document::new(result).map_err(Error::from)
|
||||
}
|
||||
}
|
||||
|
|
@ -1500,7 +1495,7 @@ foo: { bar: abc }
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_preserves_structure() {
|
||||
fn test_remove_preserves_block_structure() {
|
||||
let original = r#"
|
||||
permissions:
|
||||
contents: read # Keep this comment
|
||||
|
|
@ -1525,6 +1520,47 @@ permissions:
|
|||
");
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_remove_preserves_flow_structure() {
|
||||
// let original = "foo: { a: a, b: b }";
|
||||
|
||||
// let document = yamlpath::Document::new(original).unwrap();
|
||||
|
||||
// let operations = vec![Patch {
|
||||
// route: route!("foo", "b"),
|
||||
// operation: Op::Remove,
|
||||
// }];
|
||||
|
||||
// let result = apply_yaml_patches(&document, &operations).unwrap();
|
||||
|
||||
// // Removes the key while preserving the rest of the structure
|
||||
// insta::assert_snapshot!(result.source(), @"foo: { a: a }");
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn test_remove_empty_key() {
|
||||
let original = r#"
|
||||
foo:
|
||||
bar: abc
|
||||
baz:
|
||||
"#;
|
||||
|
||||
let document = yamlpath::Document::new(original).unwrap();
|
||||
|
||||
let operations = vec![Patch {
|
||||
route: route!("foo", "baz"),
|
||||
operation: Op::Remove,
|
||||
}];
|
||||
|
||||
let result = apply_yaml_patches(&document, &operations).unwrap();
|
||||
|
||||
// Removes the empty key while preserving the rest of the structure
|
||||
insta::assert_snapshot!(result.source(), @r"
|
||||
foo:
|
||||
bar: abc
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_operations_preserve_comments() {
|
||||
let original = r#"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue