Skip to main content

omena_query/
fragments.rs

1use super::*;
2
3pub fn summarize_omena_query_fragment_bundle(input: &EngineInputV2) -> OmenaQueryFragmentBundleV0 {
4    OmenaQueryFragmentBundleV0 {
5        schema_version: "0",
6        product: "omena-query.fragment-bundle",
7        input_version: input.version.clone(),
8        expression_semantics: summarize_omena_query_expression_semantics_query_fragments(input),
9        source_resolution: summarize_omena_query_source_resolution_query_fragments(input),
10        selector_usage: summarize_omena_query_selector_usage_query_fragments(input),
11    }
12}
13
14pub fn summarize_omena_query_expression_semantics_query_fragments(
15    input: &EngineInputV2,
16) -> ExpressionSemanticsQueryFragmentsV0 {
17    summarize_expression_semantics_query_fragments_input(input)
18}
19
20pub fn summarize_omena_query_expression_domain_flow_analysis(
21    input: &EngineInputV2,
22) -> ExpressionDomainFlowAnalysisV0 {
23    summarize_expression_domain_flow_analysis_input(input)
24}
25
26pub fn summarize_omena_query_expression_domain_control_flow_analysis(
27    input: &EngineInputV2,
28) -> ExpressionDomainControlFlowAnalysisV0 {
29    summarize_expression_domain_control_flow_analysis_input(input)
30}
31
32pub fn summarize_omena_query_expression_domain_call_site_flow_analysis(
33    input: &EngineInputV2,
34) -> ExpressionDomainCallSiteFlowAnalysisV0 {
35    summarize_expression_domain_call_site_flow_analysis_input(input)
36}
37
38pub fn summarize_omena_query_expression_domain_provenance_explanations(
39    input: &EngineInputV2,
40) -> ExpressionDomainProvenanceExplanationsV0 {
41    summarize_expression_domain_provenance_explanations_input(input)
42}
43
44pub fn summarize_omena_query_expression_domain_reduced_product_iteration(
45    input: &EngineInputV2,
46) -> ExpressionDomainReducedProductIterationV0 {
47    summarize_expression_domain_reduced_product_iteration_input(input)
48}
49
50pub fn summarize_omena_query_expression_domain_incremental_flow_analysis(
51    input: &EngineInputV2,
52    runtime: &mut OmenaQueryExpressionDomainFlowRuntimeV0,
53) -> OmenaQueryExpressionDomainIncrementalFlowAnalysisV0 {
54    runtime.analyze_input(input)
55}
56
57pub fn summarize_omena_query_expression_domain_selector_projection(
58    input: &EngineInputV2,
59) -> OmenaQueryExpressionDomainSelectorProjectionV0 {
60    let style_selectors_by_path = style_selector_universe_by_path(input);
61    let expression_targets = expression_target_style_paths(input);
62    let flow_analysis = summarize_omena_query_expression_domain_flow_analysis(input);
63    let mut projections = Vec::new();
64
65    for graph in flow_analysis.analyses {
66        for node in graph.analysis.nodes {
67            let target_style_paths = target_style_paths_for_flow_node(
68                node.id.as_str(),
69                node.predecessor_ids.as_slice(),
70                &expression_targets,
71            );
72            let selector_universe = selector_universe_for_targets(
73                target_style_paths.as_slice(),
74                &style_selectors_by_path,
75            );
76            let projection = project_abstract_value_selectors(&node.value, &selector_universe);
77            projections.push(OmenaQueryExpressionDomainSelectorProjectionEntryV0 {
78                graph_id: graph.graph_id.clone(),
79                file_path: graph.file_path.clone(),
80                node_id: node.id,
81                target_style_paths,
82                value_kind: node.value_kind,
83                reduced_product: summarize_reduced_class_value_product(&node.value),
84                selector_names: projection.selector_names,
85                certainty: projection.certainty,
86            });
87        }
88    }
89
90    OmenaQueryExpressionDomainSelectorProjectionV0 {
91        schema_version: "0",
92        product: "omena-query.expression-domain-selector-projection",
93        input_version: input.version.clone(),
94        projection_count: projections.len(),
95        projections,
96    }
97}
98
99impl OmenaQueryExpressionDomainFlowRuntimeV0 {
100    pub fn revision(&self) -> u64 {
101        self.revision
102    }
103
104    pub fn graph_count(&self) -> usize {
105        self.databases_by_graph_id.len()
106    }
107
108    pub fn analyze_input(
109        &mut self,
110        input: &EngineInputV2,
111    ) -> OmenaQueryExpressionDomainIncrementalFlowAnalysisV0 {
112        self.revision += 1;
113        let revision = self.revision;
114        let flow_graphs = collect_expression_domain_flow_graphs(input);
115        let live_graph_ids = flow_graphs
116            .iter()
117            .map(|entry| entry.graph_id.clone())
118            .collect::<BTreeSet<_>>();
119
120        self.databases_by_graph_id
121            .retain(|graph_id, _| live_graph_ids.contains(graph_id));
122        self.previous_analyses_by_graph_id
123            .retain(|graph_id, _| live_graph_ids.contains(graph_id));
124
125        let analyses = flow_graphs
126            .into_iter()
127            .map(|entry| {
128                let database = self
129                    .databases_by_graph_id
130                    .entry(entry.graph_id.clone())
131                    .or_default();
132                let previous_analysis = self.previous_analyses_by_graph_id.get(&entry.graph_id);
133                let analysis = analyze_class_value_flow_incremental_with_database(
134                    &entry.graph,
135                    database,
136                    previous_analysis,
137                    revision,
138                );
139                self.previous_analyses_by_graph_id
140                    .insert(entry.graph_id.clone(), analysis.analysis.clone());
141
142                OmenaQueryExpressionDomainIncrementalFlowAnalysisEntryV0 {
143                    graph_id: entry.graph_id,
144                    file_path: entry.file_path,
145                    analysis,
146                }
147            })
148            .collect::<Vec<_>>();
149
150        let dirty_graph_count = analyses
151            .iter()
152            .filter(|entry| entry.analysis.incremental_plan.dirty_node_count > 0)
153            .count();
154        let reused_graph_count = analyses
155            .iter()
156            .filter(|entry| entry.analysis.reused_previous_analysis)
157            .count();
158
159        OmenaQueryExpressionDomainIncrementalFlowAnalysisV0 {
160            schema_version: "0",
161            product: "omena-query.expression-domain-incremental-flow-analysis",
162            input_version: input.version.clone(),
163            revision,
164            graph_count: analyses.len(),
165            dirty_graph_count,
166            reused_graph_count,
167            analyses,
168        }
169    }
170}
171
172fn expression_target_style_paths(input: &EngineInputV2) -> BTreeMap<String, String> {
173    input
174        .sources
175        .iter()
176        .flat_map(|source| source.document.class_expressions.iter())
177        .map(|expression| (expression.id.clone(), expression.scss_module_path.clone()))
178        .collect()
179}
180
181fn style_selector_universe_by_path(input: &EngineInputV2) -> BTreeMap<String, Vec<String>> {
182    input
183        .styles
184        .iter()
185        .map(|style| {
186            let selector_names = style
187                .document
188                .selectors
189                .iter()
190                .map(|selector| {
191                    selector
192                        .canonical_name
193                        .clone()
194                        .unwrap_or_else(|| selector.name.clone())
195                })
196                .collect::<BTreeSet<_>>()
197                .into_iter()
198                .collect::<Vec<_>>();
199            (style.file_path.clone(), selector_names)
200        })
201        .collect()
202}
203
204fn target_style_paths_for_flow_node(
205    node_id: &str,
206    predecessor_ids: &[String],
207    expression_targets: &BTreeMap<String, String>,
208) -> Vec<String> {
209    let mut targets = BTreeSet::new();
210    if let Some(target) = expression_targets.get(node_id) {
211        targets.insert(target.clone());
212    }
213    for predecessor_id in predecessor_ids {
214        if let Some(target) = expression_targets.get(predecessor_id) {
215            targets.insert(target.clone());
216        }
217    }
218    targets.into_iter().collect()
219}
220
221fn selector_universe_for_targets(
222    target_style_paths: &[String],
223    style_selectors_by_path: &BTreeMap<String, Vec<String>>,
224) -> Vec<String> {
225    let mut selectors = BTreeSet::new();
226    if target_style_paths.is_empty() {
227        for selector_names in style_selectors_by_path.values() {
228            selectors.extend(selector_names.iter().cloned());
229        }
230    } else {
231        for target_style_path in target_style_paths {
232            if let Some(selector_names) = style_selectors_by_path.get(target_style_path) {
233                selectors.extend(selector_names.iter().cloned());
234            }
235        }
236    }
237    selectors.into_iter().collect()
238}
239
240pub fn summarize_omena_query_source_resolution_query_fragments(
241    input: &EngineInputV2,
242) -> SourceResolutionQueryFragmentsV0 {
243    summarize_omena_resolver_query_fragments(input)
244}
245
246pub fn summarize_omena_query_selector_usage_query_fragments(
247    input: &EngineInputV2,
248) -> SelectorUsageQueryFragmentsV0 {
249    summarize_selector_usage_query_fragments_input(input)
250}
251
252pub fn summarize_omena_query_source_resolution_canonical_producer_signal(
253    input: &EngineInputV2,
254) -> SourceResolutionCanonicalProducerSignalV0 {
255    summarize_omena_resolver_canonical_producer_signal(input)
256}
257
258pub fn summarize_omena_query_source_resolution_runtime(
259    input: &EngineInputV2,
260) -> OmenaResolverSourceResolutionRuntimeIndexV0 {
261    summarize_omena_resolver_source_resolution_runtime(input)
262}
263
264pub fn summarize_omena_query_expression_semantics_canonical_producer_signal(
265    input: &EngineInputV2,
266) -> ExpressionSemanticsCanonicalProducerSignalV0 {
267    summarize_expression_semantics_canonical_producer_signal_input(input)
268}
269
270pub fn summarize_omena_query_selector_usage_canonical_producer_signal(
271    input: &EngineInputV2,
272) -> SelectorUsageCanonicalProducerSignalV0 {
273    summarize_selector_usage_canonical_producer_signal_input(input)
274}