From 5636e9099ea0bdc43b9504d10cb029928087ce04 Mon Sep 17 00:00:00 2001 From: Yann Hamdaoui Date: Wed, 10 Apr 2024 18:48:46 +0200 Subject: [PATCH] WIP Fix tests, don't start mangled names with `___` (for now, see Nickel bug), put predicate lib under a mangled name as well. TODO: fixpoint for the reachability of definitons and properties: when building the environment, converting definitions might create new usages of other definitions! --- src/contracts.rs | 12 ++- src/definitions.rs | 156 +++++++++++++++++---------- src/lib.rs | 34 ++++-- src/predicates.rs | 71 ++++++------ tests/json_schema_test_suite_test.rs | 11 +- 5 files changed, 178 insertions(+), 106 deletions(-) diff --git a/src/contracts.rs b/src/contracts.rs index 2ed3b1f..0589d65 100644 --- a/src/contracts.rs +++ b/src/contracts.rs @@ -47,6 +47,7 @@ use crate::{ definitions::{self, RefsUsage}, predicates::{AsPredicate, Predicate}, utils::static_access, + PREDICATES_LIBRARY, }; fn only_ignored_fields(extensions: &BTreeMap) -> bool { @@ -75,6 +76,11 @@ impl Contract { .try_as_contract(&mut refs_usage) .map(|ctr| (ctr, refs_usage)) } + + /// Return the `Dyn` contract, always succeeding. + pub fn dynamic() -> Self { + Term::Type(TypeF::Dyn.into()).into() + } } /// [TryAsContract] is essentially like `TryInto` but passes additional state around used for @@ -329,7 +335,7 @@ impl From for Contract { impl From for RichTerm { fn from(Contract(c): Contract) -> Self { match c.as_slice() { - [] => static_access("predicates", ["always"]).into(), + [] => static_access(PREDICATES_LIBRARY, ["always"]).into(), // TODO: shouldn't need to clone here [rt] => rt.clone(), _ => { @@ -356,7 +362,7 @@ impl From<&InstanceType> for Contract { fn from(value: &InstanceType) -> Contract { match value { InstanceType::Null => Contract::from(Predicate::from(mk_app!( - static_access("predicates", ["isType"]), + static_access(PREDICATES_LIBRARY, ["isType"]), Term::Enum("Null".into()) ))), InstanceType::Boolean => Contract::from(TypeF::Bool), @@ -461,7 +467,7 @@ impl From for Contract { // messages) fn from(pred: Predicate) -> Self { mk_app!( - static_access("predicates", ["contract_from_predicate"]), + static_access(PREDICATES_LIBRARY, ["contract_from_predicate"]), pred ) .into() diff --git a/src/definitions.rs b/src/definitions.rs index b9130e3..31f755a 100644 --- a/src/definitions.rs +++ b/src/definitions.rs @@ -39,7 +39,6 @@ use nickel_lang_core::{ record::{Field, FieldMetadata, RecordData}, LetAttrs, RichTerm, Term, }, - typ::TypeF, }; use schemars::schema::{RootSchema, Schema, SchemaObject}; @@ -47,7 +46,7 @@ use crate::{ contracts::{Contract, Documentation}, predicates::Predicate, utils::{decode_json_ptr_part, static_access}, - DEFINITIONS_MANGLED, PROPS_PREDICATES_MANGLED, + DEFINITIONS_MANGLED, ENVIRONMENT_MANGLED, PROPS_PREDICATES_MANGLED, }; /// Specify if a reference is used in a context which requires a contract or a predicate. @@ -153,39 +152,35 @@ pub struct ConvertedDef { contract: Option, } -/// The conversion of a JSON schema property into a Nickel predicate. -#[derive(Clone)] -pub struct ConvertedProp { - doc: Option, - predicate: Predicate, -} - - impl ConvertedDef { - /// Convert the contract part of this definition to a record field with the appropriate - /// definition. This method returns `None` if `self.contract` is `None`. - pub fn contract_as_field(&self) -> Option { - self.as_field(&self.contract) + /// Take the contract part out of this definition and convert it to a record field with the + /// appropriate definition. This method returns `None` if `self.contract` is `None`. + /// + /// After calling this method, `self.contract` will be `None`. + pub fn contract_as_field(&mut self) -> Option { + Self::as_field(self.contract.take(), self.doc.clone()) } - /// Convert the contract part of this definition to a record field with the appropriate - /// definition. This method returns `None` if `self.contract` is `None`. - pub fn predicate_as_field(&self) -> Option { - self.as_field(&self.predicate) + /// Take the predicate part out of this definition and convert it to a record field with the + /// appropriate definition. This method returns `None` if `self.contract` is `None`. + /// + /// After calling this method, `self.predicate` will be `None`. + pub fn predicate_as_field(&mut self) -> Option { + Self::as_field(self.predicate.take(), self.doc.clone()) } /// Helper including the logic common to `contract_as_field` and `predicate_as_field`. - fn as_field(&self, value: &Option) -> Option + fn as_field(value: Option, doc: Option) -> Option where RichTerm: From, V: Clone, { - let value = RichTerm::from(value.as_ref()?.clone()); + let value = RichTerm::from(value?); Some(Field { value: Some(value), metadata: FieldMetadata { - doc: self.doc.clone().map(String::from), + doc: doc.map(String::from), ..Default::default() }, ..Default::default() @@ -193,6 +188,26 @@ impl ConvertedDef { } } +/// The conversion of a JSON schema property into a Nickel predicate. +#[derive(Clone)] +pub struct ConvertedProp { + doc: Option, + predicate: Predicate, +} + +impl From for Field { + fn from(value: ConvertedProp) -> Self { + Field { + value: Some(value.predicate.into()), + metadata: FieldMetadata { + doc: value.doc.map(String::from), + ..Default::default() + }, + ..Default::default() + } + } +} + /// State recording which properties and definitions are actually used and how (as predicates or as /// contracts). #[derive(Clone, Default)] @@ -252,8 +267,8 @@ pub fn resolve_ref(reference: &str, state: &mut RefsUsage, usage: RefUsage) -> R ); match usage { - RefUsage::Contract => Term::Type(TypeF::Dyn.into()).into(), - RefUsage::Predicate => static_access("predicates", ["always"]), + RefUsage::Contract => Contract::dynamic().into(), + RefUsage::Predicate => Predicate::always().into(), } }; @@ -271,8 +286,8 @@ pub fn resolve_ref(reference: &str, state: &mut RefsUsage, usage: RefUsage) -> R // as a separator as a key. See the documentation of `PROPS_PREDICATES_MANGLED` // for more information. static_access( - PROPS_PREDICATES_MANGLED, - [field_path.path.join("/").as_str()], + ENVIRONMENT_MANGLED, + [PROPS_PREDICATES_MANGLED, field_path.path.join("/").as_str()], ) } } @@ -280,11 +295,17 @@ pub fn resolve_ref(reference: &str, state: &mut RefsUsage, usage: RefUsage) -> R match usage { RefUsage::Contract => { state.defs_contracts.insert(name.clone()); - static_access(DEFINITIONS_MANGLED, [name.as_ref(), "contract"]) + static_access( + ENVIRONMENT_MANGLED, + [DEFINITIONS_MANGLED, "contracts", name.as_ref()], + ) } RefUsage::Predicate => { state.defs_predicates.insert(name.clone()); - static_access(DEFINITIONS_MANGLED, [name.as_ref(), "predicate"]) + static_access( + ENVIRONMENT_MANGLED, + [DEFINITIONS_MANGLED, "predicates", name.as_ref()], + ) } } } else { @@ -371,49 +392,70 @@ impl Environment { /// Wrap a Nickel [`RichTerm`] in a let binding containing the definitions /// from the environment. This is necessary for the Nickel access terms /// tracked in the environment to actually work. - pub fn wrap(self, inner: RichTerm) -> RichTerm { + pub fn wrap(mut self, inner: RichTerm) -> RichTerm { let contracts = self .definitions - .iter() + .iter_mut() .filter_map(|(k, v)| Some((Ident::from(k), v.contract_as_field()?))) .collect(); let predicates = self .definitions - .iter() - .filter_map(|(k, v)| Some((Ident::from(k), v.predicate_as_field()?))) + .into_iter() + .filter_map(|(k, mut v)| Some((Ident::from(k), v.predicate_as_field()?))) .collect(); let prop_preds = self .property_preds - .iter() - .filter_map(|(k, v)| Some((Ident::from(k.join("/")), v.clone()))) + .into_iter() + .filter_map(|(k, v)| Some((Ident::from(k.join("/")), Field::from(v)))) + .collect(); + + // All the definitions as a Nickel record + let defs = Term::Record(RecordData::with_field_values( + [ + ( + Ident::from("contracts"), + Term::Record(RecordData { + fields: contracts, + ..Default::default() + }) + .into(), + ), + ( + Ident::from("predicates"), + Term::Record(RecordData { + fields: predicates, + ..Default::default() + }) + .into(), + ), + ] + .into_iter() + .collect(), + )) + .into(); + + // All the properties (predicates) as a Nickel record + let props = Term::Record(RecordData { + fields: prop_preds, + ..Default::default() + }) + .into(); + + // The enclosing record, with one field for the definitions and one for the properties + let global_env = Term::Record(RecordData::with_field_values( + [ + (Ident::from(DEFINITIONS_MANGLED), defs), + (Ident::from(PROPS_PREDICATES_MANGLED), props), + ] + .into_iter() + .collect(), + )); Term::Let( - "definitions".into(), - Term::Record(RecordData::with_field_values( - [ - ( - Ident::from("contracts"), - Term::Record(RecordData { - fields: contracts, - ..Default::default() - }) - .into(), - ), - ( - Ident::from("predicates"), - Term::Record(RecordData { - fields: predicates, - ..Default::default() - }) - .into(), - ), - ] - .into_iter() - .collect(), - )) - .into(), + Ident::from(ENVIRONMENT_MANGLED), + global_env.into(), inner, LetAttrs { rec: true, diff --git a/src/lib.rs b/src/lib.rs index cf16690..38b9fac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,7 @@ pub mod definitions; pub mod predicates; pub(crate) mod utils; -use contracts::{AsCtrThruPred, Contract, TryAsContract}; +use contracts::Contract; use definitions::Environment; use nickel_lang_core::{ cache::{Cache, ErrorTolerance}, @@ -34,6 +34,21 @@ use nickel_lang_core::{ use predicates::Predicate; use schemars::schema::RootSchema; +/// The top-level variable storing the json-schema-to-nickel predicate library included by default +/// in any generated contract. +pub const PREDICATES_LIBRARY: &str = "_js2n_nickel_preds_lib"; + +/// The top-level variable storing the environment, that is the definitions and the properties +/// referenced in the JSON schema (through the `$ref`) attribute. This variable stores +/// [DEFINITIONS_MANGLED] and [PROPS_PREDICATES_MANGLED], each in their own field. +/// +/// We put both under the same variable so that definitions and properties are accessible from +/// everywhere, including from other definitions and properties (in fact, we would like to have +/// mutual recursive let definitions for [DEFINITIONS_MANGLED] and [PROPS_PREDICATES_MANGLED], but +/// Nickel doesn't have mutually recursive lets, so we put both in a recursive record instead). +// pub const ENVIRONMENT_MANGLED: &str = "___js2n_nickel_global_env"; +pub const ENVIRONMENT_MANGLED: &str = "_js2n_nickel_global_env"; + /// The name of the special variable introduced by json-schema-to-nickel in the final contract /// which holds the predicates and the contracts corresponding to the definitions of the schema. /// The name is long and specific on purpose as it could clash with existing variable in the @@ -42,7 +57,8 @@ use schemars::schema::RootSchema; /// This Nickel variable is expected to have the type /// `{_ : {predicate: _, contract: _}}` where field names correspond to the top-level /// definitions in the schema. -pub const DEFINITIONS_MANGLED: &str = "___js2n_nickel_defs"; +// pub const DEFINITIONS_MANGLED: &str = "___js2n_nickel_defs"; +pub const DEFINITIONS_MANGLED: &str = "_js2n_nickel_defs"; /// Same as [DEFINITIONS_MANGLED] but for the predicates corresponding to properties of the schema. /// @@ -53,19 +69,19 @@ pub const DEFINITIONS_MANGLED: &str = "___js2n_nickel_defs"; /// Properties can be nested, so we might need to store both a predicate for `foo` and for /// `foo.bar.baz`. To make this work, we store the predicates in a flat dictionary, where the keys /// are complete paths using `/` as a separator (to avoid confusion with Nickel field path). -pub const PROPS_PREDICATES_MANGLED: &str = "___js2n_nickel_prop_preds"; +// pub const PROPS_PREDICATES_MANGLED: &str = "___js2n_nickel_prop_preds"; +pub const PROPS_PREDICATES_MANGLED: &str = "_js2n_nickel_prop_preds"; /// Convert a [`RootSchema`] into a Nickel contract. If the JSON schema is /// representable as a lazy record contract, this conversion is preferred. /// Otherwise, we fall back to generating a predicate. -pub fn root_schema(root: &RootSchema) -> RichTerm { - let env = Environment::new(todo!(), todo!()); - - let (contract, refs_usage) = Contract::from_root_schema(root).unwrap_or_else(|| { - let (predicate, refs_usage) = Predicate::from_root_schema(root); +pub fn root_schema(root_schema: &RootSchema) -> RichTerm { + let (contract, refs_usage) = Contract::from_root_schema(root_schema).unwrap_or_else(|| { + let (predicate, refs_usage) = Predicate::from_root_schema(root_schema); (Contract::from(predicate), refs_usage) }); + let env = Environment::new(root_schema, &refs_usage); wrap_contract(env, contract) } @@ -82,7 +98,7 @@ pub fn wrap_contract(env: Environment, contract: Contract) -> RichTerm { let lib_rt = parser.parse_strict(file_id, lexer).unwrap(); Term::Let( - "predicates".into(), + PREDICATES_LIBRARY.into(), lib_rt, env.wrap(contract.into()), Default::default(), diff --git a/src/predicates.rs b/src/predicates.rs index 54a7da2..55e74f5 100644 --- a/src/predicates.rs +++ b/src/predicates.rs @@ -23,18 +23,26 @@ use serde_json::Value; use crate::{ definitions::{self, RefsUsage}, utils::static_access, + PREDICATES_LIBRARY, }; #[derive(Clone)] pub struct Predicate(RichTerm); impl Predicate { + /// Convert a full JSON schema to a predicate. Returns the predicate and the `$refs` that were + /// referenced during the conversion. pub fn from_root_schema(root: &RootSchema) -> (Self, RefsUsage) { let mut refs_usage = RefsUsage::default(); let predicate = root.schema.as_predicate(&mut refs_usage); (predicate, refs_usage) } + + /// Return an always succeeding predicate. + pub fn always() -> Self { + static_access(PREDICATES_LIBRARY, ["always"]).into() + } } /// [AsPredicate] is essentially like `Into` but passes additional state around used for @@ -97,7 +105,7 @@ impl IntoIterator for Predicates { fn or_always(s: Option<&Schema>, refs_usage: &mut RefsUsage) -> Predicate { s.map(|s| s.as_predicate(refs_usage)) - .unwrap_or(Predicate::from(static_access("predicates", ["always"]))) + .unwrap_or(Predicate::always()) } impl From<&InstanceType> for Predicate { @@ -111,7 +119,7 @@ impl From<&InstanceType> for Predicate { InstanceType::String => Term::Enum("String".into()), InstanceType::Integer => Term::Enum("Integer".into()), }; - mk_app!(static_access("predicates", ["isType"]), type_tag).into() + mk_app!(static_access(PREDICATES_LIBRARY, ["isType"]), type_tag).into() } } @@ -120,7 +128,7 @@ impl From<&SingleOrVec> for Predicate { match value { SingleOrVec::Single(t) => t.as_ref().into(), SingleOrVec::Vec(ts) => mk_app!( - static_access("predicates", ["anyOf"]), + static_access(PREDICATES_LIBRARY, ["anyOf"]), Term::Array( Array::new(ts.iter().map(|t| Predicate::from(t).into()).collect()), Default::default() @@ -136,7 +144,7 @@ impl From<&SingleOrVec> for Predicate { impl From<&[Value]> for Predicate { fn from(value: &[Value]) -> Self { mk_app!( - static_access("predicates", ["enum"]), + static_access(PREDICATES_LIBRARY, ["enum"]), Term::Array( Array::new( value @@ -156,7 +164,7 @@ impl From<&[Value]> for Predicate { impl From<&Value> for Predicate { fn from(value: &Value) -> Self { Term::App( - static_access("predicates", ["const"]), + static_access(PREDICATES_LIBRARY, ["const"]), serde_json::from_value(value.clone()).unwrap(), ) .into() @@ -167,7 +175,7 @@ fn mk_all_of(preds: impl IntoIterator) -> Predicate { let mut ps = preds.into_iter(); match (ps.next(), ps.next()) { // [] - (None, _) => static_access("predicates", ["always"]).into(), + (None, _) => Predicate::always(), // [p] (Some(p), None) => p, // ps @@ -175,7 +183,7 @@ fn mk_all_of(preds: impl IntoIterator) -> Predicate { // reconstruct the full iterator let ps = iter::once(p1).chain(iter::once(p2)).chain(ps); mk_app!( - static_access("predicates", ["allOf"]), + static_access(PREDICATES_LIBRARY, ["allOf"]), Term::Array(Array::from_iter(ps.map(RichTerm::from)), Default::default()) ) .into() @@ -187,7 +195,7 @@ fn mk_any_of(preds: impl IntoIterator) -> Predicate { let mut ps = preds.into_iter(); match (ps.next(), ps.next()) { // [] - (None, _) => static_access("predicates", ["always"]).into(), + (None, _) => Predicate::always(), // [p] (Some(p), None) => p, // ps @@ -195,7 +203,7 @@ fn mk_any_of(preds: impl IntoIterator) -> Predicate { // reconstruct the full iterator let ps = iter::once(p1).chain(iter::once(p2)).chain(ps); mk_app!( - static_access("predicates", ["anyOf"]), + static_access(PREDICATES_LIBRARY, ["anyOf"]), Term::Array(Array::from_iter(ps.map(RichTerm::from)), Default::default()) ) .into() @@ -229,7 +237,7 @@ impl AsPredicates for SubschemaValidation { .as_deref() .map(|schemas| { mk_app!( - static_access("predicates", ["oneOf"]), + static_access(PREDICATES_LIBRARY, ["oneOf"]), Term::Array( Array::new( schemas @@ -248,7 +256,7 @@ impl AsPredicates for SubschemaValidation { .as_deref() .map(|s| { mk_app!( - static_access("predicates", ["not"]), + static_access(PREDICATES_LIBRARY, ["not"]), s.as_predicate(refs_usage) ) .into() @@ -259,7 +267,7 @@ impl AsPredicates for SubschemaValidation { .as_deref() .map(move |if_schema| { mk_app!( - static_access("predicates", ["ifThenElse"]), + static_access(PREDICATES_LIBRARY, ["ifThenElse"]), if_schema.as_predicate(refs_usage), or_always(then_schema.as_deref(), refs_usage), or_always(else_schema.as_deref(), refs_usage) @@ -292,7 +300,7 @@ impl From<&NumberValidation> for Predicates { fn predicate(s: &str) -> impl '_ + FnOnce(f64) -> Predicate { move |n| { mk_app!( - static_access("predicates", ["numbers", s]), + static_access(PREDICATES_LIBRARY, ["numbers", s]), Term::Num(Number::try_from_float_simplest(n).unwrap()) ) .into() @@ -331,7 +339,7 @@ impl From<&StringValidation> for Predicates { let max_length = max_length .map(|n| { mk_app!( - static_access("predicates", ["strings", "maxLength"]), + static_access(PREDICATES_LIBRARY, ["strings", "maxLength"]), Term::Num(n.into()) ) .into() @@ -341,7 +349,7 @@ impl From<&StringValidation> for Predicates { let min_length = min_length .map(|n| { mk_app!( - static_access("predicates", ["strings", "minLength"]), + static_access(PREDICATES_LIBRARY, ["strings", "minLength"]), Term::Num(n.into()) ) .into() @@ -352,7 +360,7 @@ impl From<&StringValidation> for Predicates { .as_deref() .map(|s| { mk_app!( - static_access("predicates", ["strings", "pattern"]), + static_access(PREDICATES_LIBRARY, ["strings", "pattern"]), make::string(s) ) .into() @@ -377,14 +385,14 @@ impl AsPredicates for ArrayValidation { let items = match items { None => vec![], Some(SingleOrVec::Single(s)) => vec![mk_app!( - static_access("predicates", ["arrays", "arrayOf"]), + static_access(PREDICATES_LIBRARY, ["arrays", "arrayOf"]), s.as_predicate(refs_usage) ) .into()], Some(SingleOrVec::Vec(schemas)) => { let len = schemas.len(); [mk_app!( - static_access("predicates", ["arrays", "items"]), + static_access(PREDICATES_LIBRARY, ["arrays", "items"]), Term::Array( Array::new( schemas @@ -399,7 +407,7 @@ impl AsPredicates for ArrayValidation { .into_iter() .chain(additional_items.as_deref().map(|s| { mk_app!( - static_access("predicates", ["arrays", "additionalItems"]), + static_access(PREDICATES_LIBRARY, ["arrays", "additionalItems"]), s.as_predicate(refs_usage), Term::Num(len.into()) ) @@ -413,7 +421,7 @@ impl AsPredicates for ArrayValidation { let max_items = max_items .map(|n| { mk_app!( - static_access("predicates", ["arrays", "maxItems"]), + static_access(PREDICATES_LIBRARY, ["arrays", "maxItems"]), Term::Num(n.into()) ) .into() @@ -423,7 +431,7 @@ impl AsPredicates for ArrayValidation { let min_items = min_items .map(|n| { mk_app!( - static_access("predicates", ["arrays", "minItems"]), + static_access(PREDICATES_LIBRARY, ["arrays", "minItems"]), Term::Num(n.into()) ) .into() @@ -432,7 +440,8 @@ impl AsPredicates for ArrayValidation { let unique_items = unique_items .and_then(|unique| { - unique.then_some(static_access("predicates", ["arrays", "uniqueItems"]).into()) + unique + .then_some(static_access(PREDICATES_LIBRARY, ["arrays", "uniqueItems"]).into()) }) .into_iter(); @@ -440,7 +449,7 @@ impl AsPredicates for ArrayValidation { .as_deref() .map(|s| { mk_app!( - static_access("predicates", ["arrays", "contains"]), + static_access(PREDICATES_LIBRARY, ["arrays", "contains"]), s.as_predicate(refs_usage) ) .into() @@ -473,7 +482,7 @@ impl AsPredicates for ObjectValidation { let max_properties = max_properties .map(|n| { mk_app!( - static_access("predicates", ["records", "maxProperties"]), + static_access(PREDICATES_LIBRARY, ["records", "maxProperties"]), Term::Num(n.into()) ) .into() @@ -483,7 +492,7 @@ impl AsPredicates for ObjectValidation { let min_properties = min_properties .map(|n| { mk_app!( - static_access("predicates", ["records", "minProperties"]), + static_access(PREDICATES_LIBRARY, ["records", "minProperties"]), Term::Num(n.into()) ) .into() @@ -494,7 +503,7 @@ impl AsPredicates for ObjectValidation { .as_deref() .map(|s| { mk_app!( - static_access("predicates", ["records", "propertyNames"]), + static_access(PREDICATES_LIBRARY, ["records", "propertyNames"]), s.as_predicate(refs_usage) ) .into() @@ -507,7 +516,7 @@ impl AsPredicates for ObjectValidation { } else { Some( mk_app!( - static_access("predicates", ["records", "required"]), + static_access(PREDICATES_LIBRARY, ["records", "required"]), Term::Array( Array::new(required.iter().map(make::string).collect()), Default::default() @@ -520,7 +529,7 @@ impl AsPredicates for ObjectValidation { .into_iter(); let record = [mk_app!( - static_access("predicates", ["records", "record"]), + static_access(PREDICATES_LIBRARY, ["records", "record"]), Term::Record(RecordData::with_field_values( properties .iter() @@ -562,7 +571,7 @@ fn dependencies( .and_then(|v| v.as_object()) .map(|deps| { mk_app!( - static_access("predicates", ["records", "dependencies"]), + static_access(PREDICATES_LIBRARY, ["records", "dependencies"]), Term::Record(RecordData::with_field_values( deps.into_iter() .map(|(key, value)| ( @@ -652,8 +661,8 @@ impl AsPredicate for SchemaObject { impl AsPredicate for Schema { fn as_predicate(&self, refs_usage: &mut RefsUsage) -> Predicate { match self { - Schema::Bool(true) => static_access("predicates", ["always"]).into(), - Schema::Bool(false) => static_access("predicates", ["never"]).into(), + Schema::Bool(true) => Predicate::always(), + Schema::Bool(false) => static_access(PREDICATES_LIBRARY, ["never"]).into(), Schema::Object(o) => o.as_predicate(refs_usage), } } diff --git a/tests/json_schema_test_suite_test.rs b/tests/json_schema_test_suite_test.rs index 9f83391..518e992 100644 --- a/tests/json_schema_test_suite_test.rs +++ b/tests/json_schema_test_suite_test.rs @@ -2,10 +2,9 @@ use std::io::stderr; use json_schema_test_suite::{json_schema_test_suite, TestCase}; use json_schema_to_nickel::{ - definitions::Environment, predicates::Predicate, root_schema, wrap_predicate, + definitions::Environment, predicates::Predicate, root_schema, wrap_contract, }; use nickel_lang_core::{eval::cache::lazy::CBNCache, program::Program, term::RichTerm}; -use schemars::schema::Schema; use stringreader::StringReader; #[json_schema_test_suite("vendor/JSON-Schema-Test-Suite", "draft7", { @@ -34,11 +33,11 @@ fn translation_typecheck_test( let contract = if test_case.schema.is_object() { root_schema(&dbg!(serde_json::from_value(test_case.schema).unwrap())) } else { - wrap_predicate( + wrap_contract( Environment::empty(), - Predicate::from(dbg!( - &serde_json::from_value::(test_case.schema).unwrap() - )), + Predicate::from_root_schema(dbg!(&serde_json::from_value(test_case.schema).unwrap())) + .0 + .into(), ) };