Skip to main content

omena_query/style/
origin_inputs.rs

1use omena_cascade::CascadeOriginV0;
2use omena_query_checker_orchestrator::OmenaCheckerCascadeDeclarationInputV0;
3use serde::Serialize;
4
5use super::cascade_checker::collect_query_checker_cascade_declarations;
6
7const HTML_STANDARD_USER_AGENT_SAMPLE_CSS: &str =
8    include_str!("../../data/html-standard-user-agent-sample/stylesheet.css");
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
11#[serde(rename_all = "camelCase")]
12pub struct OmenaQueryCascadeOriginStylesheetV0 {
13    pub schema_version: &'static str,
14    pub product: &'static str,
15    pub source_name: String,
16    pub origin: CascadeOriginV0,
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub source_url: Option<String>,
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub source_pin: Option<String>,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub license: Option<&'static str>,
23    pub declarations: Vec<OmenaCheckerCascadeDeclarationInputV0>,
24}
25
26pub fn summarize_omena_query_cascade_origin_stylesheet_v0(
27    source_name: impl Into<String>,
28    source: &str,
29    origin: CascadeOriginV0,
30) -> OmenaQueryCascadeOriginStylesheetV0 {
31    let declarations = collect_query_checker_cascade_declarations(source)
32        .into_iter()
33        .map(|mut declaration| {
34            declaration.input.origin = origin;
35            declaration.input
36        })
37        .collect();
38    OmenaQueryCascadeOriginStylesheetV0 {
39        schema_version: "0",
40        product: "omena-query.cascade-origin-stylesheet",
41        source_name: source_name.into(),
42        origin,
43        source_url: None,
44        source_pin: None,
45        license: None,
46        declarations,
47    }
48}
49
50pub fn summarize_html_standard_user_agent_sample_v0() -> OmenaQueryCascadeOriginStylesheetV0 {
51    let mut summary = summarize_omena_query_cascade_origin_stylesheet_v0(
52        "html-standard-rendering-sample",
53        HTML_STANDARD_USER_AGENT_SAMPLE_CSS,
54        CascadeOriginV0::UserAgent,
55    );
56    summary.source_url =
57        Some("https://html.spec.whatwg.org/multipage/rendering.html#flow-content-3".to_string());
58    summary.source_pin = Some("whatwg/html@9377fd656f519b60524b92f09bcc9e6d937b2017".to_string());
59    summary.license = Some("BSD-3-Clause");
60    summary
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn projects_user_stylesheets_through_the_shared_cascade_input_contract() {
69        let summary = summarize_omena_query_cascade_origin_stylesheet_v0(
70            "workspace-user-styles",
71            ".card { color: green !important; }",
72            CascadeOriginV0::User,
73        );
74
75        assert_eq!(summary.declarations.len(), 1);
76        assert_eq!(summary.declarations[0].origin, CascadeOriginV0::User);
77        assert!(summary.declarations[0].important);
78        let user_json = serde_json::to_value(&summary.declarations[0]).unwrap_or_default();
79        assert_eq!(user_json.get("origin"), Some(&serde_json::json!("user")));
80
81        let author = summarize_omena_query_cascade_origin_stylesheet_v0(
82            "author-styles",
83            ".card { color: green; }",
84            CascadeOriginV0::Author,
85        );
86        let author_json = serde_json::to_value(&author.declarations[0]).unwrap_or_default();
87        assert!(author_json.get("origin").is_none());
88    }
89
90    #[test]
91    fn projects_the_licensed_html_sample_as_user_agent_input() {
92        let summary = summarize_html_standard_user_agent_sample_v0();
93
94        assert!(summary.declarations.len() >= 8);
95        assert!(
96            summary
97                .declarations
98                .iter()
99                .all(|declaration| declaration.origin == CascadeOriginV0::UserAgent)
100        );
101        assert_eq!(summary.license, Some("BSD-3-Clause"));
102        assert!(
103            summary
104                .source_pin
105                .as_deref()
106                .is_some_and(|pin| pin.starts_with("whatwg/html@"))
107        );
108    }
109}