Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actions/spelling/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,7 @@ MAINPID
majorly
MAKECMDGOALS
Makefiles
markability
markdownify
markdownlintrc
marketo
Expand Down
4 changes: 2 additions & 2 deletions lib/vector-config/src/schema/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
num::ConfigurableNumber, Configurable, ConfigurableRef, GenerateError, Metadata, ToValue,
};

use super::visitors::{DisallowedUnevaluatedPropertiesVisitor, InlineSingleUseReferencesVisitor};
use super::visitors::{DisallowUnevaluatedPropertiesVisitor, InlineSingleUseReferencesVisitor};

/// Applies metadata to the given schema.
///
Expand Down Expand Up @@ -482,7 +482,7 @@ pub fn generate_internal_tagged_variant_schema(
pub fn default_schema_settings() -> SchemaSettings {
SchemaSettings::new()
.with_visitor(InlineSingleUseReferencesVisitor::from_settings)
.with_visitor(DisallowedUnevaluatedPropertiesVisitor::from_settings)
.with_visitor(DisallowUnevaluatedPropertiesVisitor::from_settings)
}

pub fn generate_root_schema<T>() -> Result<RootSchema, GenerateError>
Expand Down
2 changes: 1 addition & 1 deletion lib/vector-config/src/schema/visitors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ mod unevaluated;
pub(self) mod test;

pub use self::inline_single::InlineSingleUseReferencesVisitor;
pub use self::unevaluated::DisallowedUnevaluatedPropertiesVisitor;
pub use self::unevaluated::DisallowUnevaluatedPropertiesVisitor;
83 changes: 62 additions & 21 deletions lib/vector-config/src/schema/visitors/unevaluated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ use super::scoped_visit::{
/// with advanced subschema validation, such as `oneOf` or `allOf`, as `unevaluatedProperties`
/// cannot simply be applied to any and all schemas indiscriminately.
#[derive(Debug, Default)]
pub struct DisallowedUnevaluatedPropertiesVisitor {
pub struct DisallowUnevaluatedPropertiesVisitor {
scope_stack: SchemaScopeStack,
eligible_to_flatten: HashMap<String, HashSet<SchemaReference>>,
}

impl DisallowedUnevaluatedPropertiesVisitor {
impl DisallowUnevaluatedPropertiesVisitor {
pub fn from_settings(_: &SchemaSettings) -> Self {
Self {
scope_stack: SchemaScopeStack::default(),
Expand All @@ -41,7 +41,7 @@ impl DisallowedUnevaluatedPropertiesVisitor {
}
}

impl Visitor for DisallowedUnevaluatedPropertiesVisitor {
impl Visitor for DisallowUnevaluatedPropertiesVisitor {
fn visit_root_schema(&mut self, root: &mut RootSchema) {
let eligible_to_flatten = build_closed_schema_flatten_eligibility_mappings(root);

Expand Down Expand Up @@ -132,7 +132,7 @@ impl Visitor for DisallowedUnevaluatedPropertiesVisitor {
}
}

impl ScopedVisitor for DisallowedUnevaluatedPropertiesVisitor {
impl ScopedVisitor for DisallowUnevaluatedPropertiesVisitor {
fn push_schema_scope<S: Into<SchemaReference>>(&mut self, scope: S) {
self.scope_stack.push(scope.into());
}
Expand Down Expand Up @@ -237,12 +237,22 @@ fn build_closed_schema_flatten_eligibility_mappings(
Schema::Object(schema) => schema,
};

debug!(
"Evaluating schema definition '{}' for markability.",
Comment thread Fixed
definition_name
);

// If a schema itself would not be considered markable, then we don't need to consider the
// eligibility between parent/child since there's nothing to drive the "now unmark the child
// schemas" logic.
if !is_markable_schema(&root_schema.definitions, parent_schema) {
debug!("Schema definition '{}' not markable.", definition_name);
continue;
} else {
debug!(
"Schema definition '{}' markable. Collecting referents.",
definition_name
);
}

// Collect all referents for this definition, which includes both property-based referents
Expand All @@ -251,6 +261,13 @@ fn build_closed_schema_flatten_eligibility_mappings(
let mut referents = HashSet::new();
get_referents(parent_schema, &mut referents);

debug!(
"Collected {} referents for '{}': {:?}",
referents.len(),
definition_name,
referents
);

// Store the parent/child mapping.
parent_to_child.insert(SchemaReference::from(definition_name), referents);
}
Expand Down Expand Up @@ -328,12 +345,14 @@ fn is_markable_schema(definitions: &Map<String, Schema>, schema: &SchemaObject)
// subschemas: { "type": "null" } and { "$ref": "#/definitions/T" }. If the schema for `T` is,
// say, just a scalar schema, instead of an object schema... then it wouldn't be marked, and in
// turn, we wouldn't need to mark the schema for `Option<T>`: there's no properties at all.
//
// We'll follow schema references in subschemas up to one level deep trying to figure this out.
if let Some(subschema) = schema.subschemas.as_ref() {
let subschemas = get_object_subschemas_from_parent(subschema).collect::<Vec<_>>();

let has_object_subschema = subschemas.iter().any(|schema| is_object_schema(schema));
debug!("{} subschemas detected.", subschemas.len());

let has_object_subschema = subschemas
.iter()
.any(|schema| is_markable_schema(definitions, schema));
let has_referenced_object_subschema = subschemas
.iter()
.map(|subschema| {
Expand All @@ -342,13 +361,35 @@ fn is_markable_schema(definitions: &Map<String, Schema>, schema: &SchemaObject)
.as_ref()
.and_then(|reference| {
let reference = get_cleaned_schema_reference(reference);
definitions.get(reference)
definitions.get(reference).map(|d| (reference, d))
Comment thread
tobz marked this conversation as resolved.
Outdated
})
.and_then(|(definition_name, schema_definition)| {
schema_definition.as_object().map(|s| (definition_name, s))
})
.map_or(false, |(name, schema)| {
debug!(
"Following schema reference '{}' for subschema markability.",
Comment thread Fixed
name
);
is_markable_schema(definitions, schema)
})
.and_then(Schema::as_object)
.map_or(false, is_object_schema)
})
.any(identity);

debug!(
"Schema {} object subschema(s) and {} referenced subschemas.",
if has_object_subschema {
"has"
} else {
"does not have"
},
Comment thread
tobz marked this conversation as resolved.
if has_referenced_object_subschema {
"has"
} else {
"does not have"
},
);

if has_object_subschema || has_referenced_object_subschema {
return true;
}
Expand Down Expand Up @@ -504,7 +545,7 @@ mod tests {

use crate::schema::visitors::test::{as_schema, assert_schemas_eq};

use super::DisallowedUnevaluatedPropertiesVisitor;
use super::DisallowUnevaluatedPropertiesVisitor;

#[test]
fn basic_object_schema() {
Expand All @@ -515,7 +556,7 @@ mod tests {
}
}));

let mut visitor = DisallowedUnevaluatedPropertiesVisitor::default();
let mut visitor = DisallowUnevaluatedPropertiesVisitor::default();
visitor.visit_root_schema(&mut actual_schema);

let expected_schema = as_schema(json!({
Expand Down Expand Up @@ -543,7 +584,7 @@ mod tests {
}
}));

let mut visitor = DisallowedUnevaluatedPropertiesVisitor::default();
let mut visitor = DisallowUnevaluatedPropertiesVisitor::default();
visitor.visit_root_schema(&mut actual_schema);

let expected_schema = as_schema(json!({
Expand Down Expand Up @@ -580,7 +621,7 @@ mod tests {
}]
}));

let mut visitor = DisallowedUnevaluatedPropertiesVisitor::default();
let mut visitor = DisallowUnevaluatedPropertiesVisitor::default();
visitor.visit_root_schema(&mut actual_schema);

let expected_schema = as_schema(json!({
Expand Down Expand Up @@ -621,7 +662,7 @@ mod tests {
}]
}));

let mut visitor = DisallowedUnevaluatedPropertiesVisitor::default();
let mut visitor = DisallowUnevaluatedPropertiesVisitor::default();
visitor.visit_root_schema(&mut actual_schema);

let expected_schema = as_schema(json!({
Expand Down Expand Up @@ -662,7 +703,7 @@ mod tests {
}]
}));

let mut visitor = DisallowedUnevaluatedPropertiesVisitor::default();
let mut visitor = DisallowUnevaluatedPropertiesVisitor::default();
visitor.visit_root_schema(&mut actual_schema);

let expected_schema = as_schema(json!({
Expand Down Expand Up @@ -696,7 +737,7 @@ mod tests {
}));
let expected_schema = actual_schema.clone();

let mut visitor = DisallowedUnevaluatedPropertiesVisitor::default();
let mut visitor = DisallowUnevaluatedPropertiesVisitor::default();
visitor.visit_root_schema(&mut actual_schema);

assert_schemas_eq(expected_schema, actual_schema);
Expand All @@ -712,7 +753,7 @@ mod tests {
"additionalProperties": false
}));

let mut visitor = DisallowedUnevaluatedPropertiesVisitor::default();
let mut visitor = DisallowUnevaluatedPropertiesVisitor::default();
visitor.visit_root_schema(&mut actual_schema);

let expected_schema = as_schema(json!({
Expand Down Expand Up @@ -758,7 +799,7 @@ mod tests {
}
}));

let mut visitor = DisallowedUnevaluatedPropertiesVisitor::default();
let mut visitor = DisallowUnevaluatedPropertiesVisitor::default();
visitor.visit_root_schema(&mut actual_schema);

let expected_schema = as_schema(json!({
Expand Down Expand Up @@ -813,7 +854,7 @@ mod tests {
}
}));

let mut visitor = DisallowedUnevaluatedPropertiesVisitor::default();
let mut visitor = DisallowUnevaluatedPropertiesVisitor::default();
visitor.visit_root_schema(&mut actual_schema);

let expected_schema = as_schema(json!({
Expand Down Expand Up @@ -879,7 +920,7 @@ mod tests {
}
}));

let mut visitor = DisallowedUnevaluatedPropertiesVisitor::default();
let mut visitor = DisallowUnevaluatedPropertiesVisitor::default();
visitor.visit_root_schema(&mut actual_schema);

// Expectations:
Expand Down