Skip to content

Commit b682152

Browse files
committed
Pass check metadata (a JSON string) into the check itself
This is so we can have multiple checks with the same Rust implementation but with slightly different behavior.
1 parent bcce8f9 commit b682152

File tree

7 files changed

+56
-15
lines changed

7 files changed

+56
-15
lines changed

fontspector-checkapi/src/check.rs

+12
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub struct Check<'a> {
4242
pub fix_source: Option<&'a dyn Fn(&Testable) -> FixFnResult>,
4343
pub applies_to: &'a str,
4444
pub flags: CheckFlags,
45+
pub _metadata: Option<&'static str>,
4546
}
4647

4748
// Are we? Really? I don't know. Let's find out...
@@ -62,6 +63,17 @@ impl<'a> Check<'a> {
6263
}
6364
}
6465

66+
/// Get the metadata for this check
67+
///
68+
/// Each check definition can declare associated metadata; this is
69+
/// interpreted as a JSON string and returned as a serde_json::Value.
70+
pub fn metadata(&self) -> serde_json::Value {
71+
#[allow(clippy::expect_used)]
72+
self._metadata
73+
.map(|s| serde_json::from_str(s).unwrap_or_else(|_| panic!("Bad JSON in {}", self.id)))
74+
.unwrap_or_default()
75+
}
76+
6577
fn clarify_result(
6678
&'a self,
6779
fn_result: CheckFnResult,

fontspector-checkapi/src/context.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
use serde_json::{Map, Value};
22

3+
use crate::Check;
4+
35
#[derive(Debug, Clone)]
46
pub struct Context {
57
pub skip_network: bool,
68
pub network_timeout: Option<u64>,
79
pub configuration: Map<String, Value>,
10+
pub check_metadata: Value,
811
}
912

1013
impl Context {
@@ -15,17 +18,18 @@ impl Context {
1518
/// as the configuration for this check.
1619
pub fn specialize(
1720
&self,
18-
checkname: &str,
21+
check: &Check,
1922
configuration: &Map<String, serde_json::Value>,
2023
) -> Self {
2124
Context {
2225
skip_network: self.skip_network,
2326
network_timeout: self.network_timeout,
2427
configuration: configuration
25-
.get(checkname)
28+
.get(check.id)
2629
.and_then(|x| x.as_object())
2730
.cloned()
2831
.unwrap_or_default(),
32+
check_metadata: check.metadata(),
2933
}
3034
}
3135
}

fontspector-checkapi/src/profile.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -97,15 +97,15 @@ impl Profile {
9797
.filter(|checkname| {
9898
included_excluded(checkname, include_checks, exclude_checks)
9999
})
100-
.map(|checkname| {
101-
(
102-
sectionname.clone(),
103-
registry.checks.get(checkname),
104-
general_context.specialize(checkname, &configuration),
105-
)
106-
})
107-
.flat_map(|(sectionname, check, context)| {
108-
check.map(|c| (sectionname, c, context))
100+
.map(|checkname| (sectionname.clone(), registry.checks.get(checkname)))
101+
.filter_map(|(sectionname, check)| {
102+
check.map(|check| {
103+
(
104+
sectionname,
105+
check,
106+
general_context.specialize(check, &configuration),
107+
)
108+
})
109109
})
110110
})
111111
.flat_map(|(sectionname, check, context): (String, &Check, Context)| {

fontspector-checkhelper/src/check.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::str::FromStr;
22

3-
use darling::Error;
4-
use darling::{ast::NestedMeta, FromMeta};
3+
use darling::{ast::NestedMeta, Error, FromMeta};
54
use proc_macro::TokenStream;
65
use proc_macro2::Span;
76
use quote::quote;
@@ -47,6 +46,7 @@ struct CheckParams {
4746
applies_to: Option<String>,
4847
hotfix: Option<Ident>,
4948
fix_source: Option<Ident>,
49+
metadata: Option<String>,
5050
}
5151

5252
pub(crate) fn check_impl(args: TokenStream, input: TokenStream) -> TokenStream {
@@ -106,7 +106,10 @@ pub(crate) fn check_impl(args: TokenStream, input: TokenStream) -> TokenStream {
106106
Implementation::CheckOne => quote!(CheckImplementation::CheckOne(&#impl_ident)),
107107
Implementation::CheckAll => quote!(CheckImplementation::CheckAll(&#impl_ident)),
108108
};
109-
109+
let metadata = match params.metadata {
110+
Some(metadata) => quote!(Some(&#metadata)),
111+
None => quote!(None),
112+
};
110113
quote!(
111114
#(#attrs)*
112115
#vis #new_sig {
@@ -124,6 +127,7 @@ pub(crate) fn check_impl(args: TokenStream, input: TokenStream) -> TokenStream {
124127
hotfix: #hotfix,
125128
fix_source: #fix_source,
126129
flags: CheckFlags::default(),
130+
_metadata: #metadata,
127131
};
128132
)
129133
.into()

fontspector-cli/src/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ fn main() {
130130
skip_network: args.skip_network,
131131
network_timeout: Some(10), // XXX
132132
configuration: Map::new(),
133+
check_metadata: serde_json::Value::Null,
133134
},
134135
configuration,
135136
&testables,

fontspector-web/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub fn check_fonts(fonts: &JsValue) -> Result<String, JsValue> {
4141
skip_network: true,
4242
network_timeout: None,
4343
configuration: serde_json::Map::new(),
44+
check_metadata: serde_json::Value::Null,
4445
};
4546
let all_testables: Vec<TestableType> = collection.collection_and_files().collect();
4647

profile-testplugin/src/lib.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,31 @@ fn validate_toml(c: &Testable, _context: &Context) -> CheckFnResult {
3232
})
3333
}
3434

35+
#[check(
36+
id = "test/test_check_metadata",
37+
title = "Check we can pass metadata from the check definition into the check",
38+
rationale = "This check is part of the example of how to create plugins.",
39+
proposal = "https://github.com/simoncozens/fontspector/commit/5fdf9750991176c8e2776557ce6c17c642c24a73",
40+
applies_to = "TTF",
41+
metadata = r#"{"foo": "bar"}"#
42+
)]
43+
fn check_metadata(_c: &Testable, context: &Context) -> CheckFnResult {
44+
if context.check_metadata.get("foo") == Some(&serde_json::Value::String("bar".to_string())) {
45+
Ok(Status::just_one_pass())
46+
} else {
47+
Ok(Status::just_one_fail(
48+
"metadata-mismatch",
49+
"Metadata mismatch",
50+
))
51+
}
52+
}
53+
3554
impl fontspector_checkapi::Plugin for Test {
3655
fn register(&self, cr: &mut Registry) -> Result<(), String> {
3756
let toml = FileType::new("*.toml");
3857
cr.register_filetype("TOML", toml);
3958

40-
cr.register_simple_profile("test", vec![validate_toml, say_hello])
59+
cr.register_simple_profile("test", vec![validate_toml, say_hello, check_metadata])
4160
}
4261
}
4362

0 commit comments

Comments
 (0)