Skip to content

Commit

Permalink
add jsonschema_validation feature
Browse files Browse the repository at this point in the history
  • Loading branch information
mmoskal committed Nov 8, 2024
1 parent e97cc08 commit 529c7b1
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 38 deletions.
8 changes: 4 additions & 4 deletions parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ rustc-hash = "2.0.0"
instant = "0.1.13"
jsonschema = { version = "0.24.0", default-features = false, optional = true }
url = "2.5.2"
lazy_static = "1.5.0"
lazy_static = { version = "1.5.0", optional = true }
regex-syntax = "0.8.5"

[features]
default = ["jsonschema_validation", "lark"]
logging = []
lark = [] # ~115k of code
jsonschema_validation = ["jsonschema"]
logging = [] # this is extensive debug logging
lark = [] # ~115k (binary)
jsonschema_validation = ["jsonschema", "lazy_static"] # ~2.5M (binary)

[lib]
crate-type = ["staticlib", "rlib", "cdylib"]
Expand Down
2 changes: 1 addition & 1 deletion parser/src/earley/from_guidance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ fn grammar_from_json(
"cannot have both json_schema and lark_grammar"
);
let opts = JsonCompileOptions { compact: false };
opts.json_to_llg_no_validate(json_schema)?
opts.json_to_llg(json_schema)?
} else {
lark_to_llguidance(input.lark_grammar.as_ref().unwrap())?
};
Expand Down
2 changes: 1 addition & 1 deletion parser/src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ fn new_constraint_json(init: &LlgConstraintInit, json_schema: *const c_char) ->
.map_err(|e| anyhow::anyhow!("Invalid JSON in json_schema: {e}"))?;
let opts = JsonCompileOptions { compact: false };
let grammar = opts
.json_to_llg_no_validate(&json_schema)
.json_to_llg(&json_schema)
.map_err(|e| anyhow::anyhow!("Error compiling JSON schema to LLG: {e}"))?;
new_constraint_core(init, grammar)
}
Expand Down
37 changes: 6 additions & 31 deletions parser/src/json.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use anyhow::{anyhow, bail, Result};
use jsonschema::Validator;
use lazy_static::lazy_static;
use serde_json::{json, Value};
use std::{collections::HashMap, vec};

Expand Down Expand Up @@ -122,7 +120,12 @@ macro_rules! cache {
impl JsonCompileOptions {
pub fn json_to_llg(&self, schema: &Value) -> Result<TopLevelGrammar> {
let mut compiler = Compiler::new(self.clone());
compiler.validate(schema)?;
#[cfg(feature = "jsonschema_validation")]
{
use crate::json_validation::validate_schema;
validate_schema(schema)?;
}

compiler.execute(schema)?;
compiler.builder.finalize()
}
Expand Down Expand Up @@ -208,28 +211,6 @@ impl OptionalField for Value {
}
}

struct DummyResolver {}
impl jsonschema::Retrieve for DummyResolver {
fn retrieve(
&self,
uri: &jsonschema::Uri<&str>,
) -> std::result::Result<Value, Box<dyn std::error::Error + Send + Sync>> {
Err(anyhow!("external resolver disabled (url: {})", uri).into())
}
}

lazy_static! {
static ref SCHEMA_VALIDATOR: Validator = {
Validator::options()
.with_draft(jsonschema::Draft::Draft7)
.with_retriever(DummyResolver {})
.build(&json!({
"$ref": "http://json-schema.org/draft-07/schema"
}))
.unwrap()
};
}

impl Compiler {
pub fn new(options: JsonCompileOptions) -> Self {
Self {
Expand All @@ -242,12 +223,6 @@ impl Compiler {
}
}

pub fn validate(&mut self, schema: &Value) -> Result<()> {
SCHEMA_VALIDATOR
.validate(schema)
.map_err(|mut e| anyhow!("Invalid schema: {}", e.next().unwrap()))
}

pub fn execute(&mut self, schema: &Value) -> Result<()> {
self.builder.add_grammar(GrammarWithLexer {
greedy_skip_rx: if self.options.compact {
Expand Down
32 changes: 32 additions & 0 deletions parser/src/json_validation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use anyhow::{anyhow, Result};
use jsonschema::Validator;
use lazy_static::lazy_static;
use serde_json::{json, Value};

struct DummyResolver {}
impl jsonschema::Retrieve for DummyResolver {
fn retrieve(
&self,
uri: &jsonschema::Uri<&str>,
) -> std::result::Result<Value, Box<dyn std::error::Error + Send + Sync>> {
Err(anyhow!("external resolver disabled (url: {})", uri).into())
}
}

lazy_static! {
static ref SCHEMA_VALIDATOR: Validator = {
Validator::options()
.with_draft(jsonschema::Draft::Draft7)
.with_retriever(DummyResolver {})
.build(&json!({
"$ref": "http://json-schema.org/draft-07/schema"
}))
.unwrap()
};
}

pub fn validate_schema(schema: &Value) -> Result<()> {
SCHEMA_VALIDATOR
.validate(schema)
.map_err(|mut e| anyhow!("Invalid schema: {}", e.next().unwrap()))
}
2 changes: 2 additions & 0 deletions parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub mod ffi;

mod grammar_builder;
mod json;
#[cfg(feature = "jsonschema_validation")]
mod json_validation;
pub use grammar_builder::{GrammarBuilder, NodeRef};
pub use json::JsonCompileOptions;
pub use tokenizer_json::token_bytes_from_tokenizer_json;
Expand Down
2 changes: 1 addition & 1 deletion sample_parser/src/minimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ fn main() {
compact: false,
};
let val = serde_json::from_str(&schema_file).expect("Invalid JSON in schema");
opts.json_to_llg_no_validate(&val)
opts.json_to_llg(&val)
.expect("Failed to convert JSON to LLG")
} else {
panic!("Unknown schema file extension")
Expand Down

0 comments on commit 529c7b1

Please sign in to comment.