1use std::collections::{BTreeMap, BTreeSet};
2
3use omena_parser::{
4 LexResult, ParseResult, ParsedAnimationFactKind, ParsedCssModuleComposesEdgeKind,
5 ParsedCssModuleComposesFactKind, ParsedCssModuleValueFactKind, ParsedIcssFactKind,
6 ParsedSassModuleEdgeFactKind, ParsedSassSymbolFactKind, ParsedSelectorFactKind,
7 ParsedStyleFacts, ParsedVariableFactKind, collect_style_facts, lex, parse,
8};
9
10use crate::*;
11
12pub(super) fn collect_omena_query_omena_parser_style_facts_raw(
13 style_source: &str,
14 dialect: OmenaParserStyleDialect,
15) -> ParsedStyleFacts {
16 collect_style_facts(style_source, dialect)
17}
18
19pub(super) fn parse_omena_query_omena_parser_style_source(
20 style_source: &str,
21 dialect: OmenaParserStyleDialect,
22) -> ParseResult {
23 parse(style_source, dialect)
24}
25
26pub(super) fn lex_omena_query_omena_parser_style_source(
27 style_source: &str,
28 dialect: OmenaParserStyleDialect,
29) -> LexResult {
30 lex(style_source, dialect)
31}
32
33pub fn summarize_omena_query_style_document(
34 style_path: &str,
35 style_source: &str,
36) -> Option<OmenaQueryStyleDocumentSummaryV0> {
37 let dialect = omena_parser_dialect_for_style_path(style_path);
38 let facts = collect_omena_query_omena_parser_style_facts_raw(style_source, dialect);
39 let mut selector_names = Vec::new();
40 let mut custom_property_decl_names = Vec::new();
41 let mut custom_property_ref_names = Vec::new();
42 let mut sass_module_use_sources = BTreeSet::new();
43 let mut sass_module_forward_sources = BTreeSet::new();
44
45 for selector in facts.selectors {
46 if selector.kind == ParsedSelectorFactKind::Class {
47 selector_names.push(selector.name);
48 }
49 }
50
51 for variable in facts.variables {
52 match variable.kind {
53 ParsedVariableFactKind::CustomPropertyDeclaration => {
54 custom_property_decl_names.push(variable.name);
55 }
56 ParsedVariableFactKind::CustomPropertyReference => {
57 custom_property_ref_names.push(variable.name);
58 }
59 _ => {}
60 }
61 }
62
63 for edge in facts.sass_module_edges {
64 match edge.kind {
65 ParsedSassModuleEdgeFactKind::Use => {
66 sass_module_use_sources.insert(edge.source);
67 }
68 ParsedSassModuleEdgeFactKind::Forward => {
69 sass_module_forward_sources.insert(edge.source);
70 }
71 ParsedSassModuleEdgeFactKind::Import => {
72 sass_module_use_sources.insert(edge.source);
73 }
74 }
75 }
76
77 Some(OmenaQueryStyleDocumentSummaryV0 {
78 schema_version: "0",
79 product: "omena-query.style-document-summary",
80 language: omena_parser_style_dialect_label(dialect),
81 selector_names,
82 custom_property_decl_names,
83 custom_property_ref_names,
84 sass_module_use_sources: sass_module_use_sources.into_iter().collect(),
85 sass_module_forward_sources: sass_module_forward_sources.into_iter().collect(),
86 diagnostic_count: facts.error_count,
87 })
88}
89
90pub fn summarize_omena_query_omena_parser_style_facts(
91 style_source: &str,
92 dialect: OmenaParserStyleDialect,
93) -> OmenaQueryOmenaParserStyleFactsV0 {
94 let facts = collect_omena_query_omena_parser_style_facts_raw(style_source, dialect);
95 let sass_symbol_resolution =
96 summarize_omena_query_sass_symbol_resolution(facts.sass_symbols.as_slice());
97 let mut class_selector_names = Vec::new();
98 let mut id_selector_names = Vec::new();
99 let mut placeholder_selector_names = Vec::new();
100 let mut keyframe_names = Vec::new();
101 let mut animation_reference_names = Vec::new();
102 let mut css_module_value_definition_names = BTreeSet::new();
103 let mut css_module_value_reference_names = BTreeSet::new();
104 let mut css_module_value_import_sources = BTreeSet::new();
105 let mut css_module_composes_target_names = BTreeSet::new();
106 let mut css_module_composes_import_sources = BTreeSet::new();
107 let mut icss_export_names = BTreeSet::new();
108 let mut icss_import_local_names = BTreeSet::new();
109 let mut icss_import_remote_names = BTreeSet::new();
110 let mut icss_import_sources = BTreeSet::new();
111 let mut variable_names = BTreeSet::new();
112 let mut sass_symbol_declaration_names = BTreeSet::new();
113 let mut sass_symbol_reference_names = BTreeSet::new();
114 let mut sass_module_use_sources = BTreeSet::new();
115 let mut sass_module_forward_sources = BTreeSet::new();
116 let mut sass_module_import_sources = BTreeSet::new();
117 let mut custom_property_names = BTreeSet::new();
118 let mut custom_property_decl_names = BTreeSet::new();
119 let mut custom_property_ref_names = BTreeSet::new();
120
121 for selector in facts.selectors {
122 match selector.kind {
123 ParsedSelectorFactKind::Class => class_selector_names.push(selector.name),
124 ParsedSelectorFactKind::Id => id_selector_names.push(selector.name),
125 ParsedSelectorFactKind::Placeholder => placeholder_selector_names.push(selector.name),
126 }
127 }
128
129 for variable in facts.variables {
130 match variable.kind {
131 ParsedVariableFactKind::ScssDeclaration
132 | ParsedVariableFactKind::ScssReference
133 | ParsedVariableFactKind::LessDeclaration
134 | ParsedVariableFactKind::LessReference => {
135 variable_names.insert(variable.name);
136 }
137 ParsedVariableFactKind::CustomPropertyDeclaration
138 | ParsedVariableFactKind::CustomPropertyReference => {
139 custom_property_names.insert(variable.name.clone());
140 match variable.kind {
141 ParsedVariableFactKind::CustomPropertyDeclaration => {
142 custom_property_decl_names.insert(variable.name);
143 }
144 ParsedVariableFactKind::CustomPropertyReference => {
145 custom_property_ref_names.insert(variable.name);
146 }
147 _ => {}
148 }
149 }
150 }
151 }
152
153 for symbol in &facts.sass_symbols {
154 match symbol.role {
155 "declaration" => {
156 sass_symbol_declaration_names.insert(symbol.name.clone());
157 }
158 _ => {
159 sass_symbol_reference_names.insert(symbol.name.clone());
160 }
161 }
162 }
163
164 for edge in &facts.sass_module_edges {
165 match edge.kind {
166 ParsedSassModuleEdgeFactKind::Use => {
167 sass_module_use_sources.insert(edge.source.clone());
168 }
169 ParsedSassModuleEdgeFactKind::Forward => {
170 sass_module_forward_sources.insert(edge.source.clone());
171 }
172 ParsedSassModuleEdgeFactKind::Import => {
173 sass_module_import_sources.insert(edge.source.clone());
174 }
175 }
176 }
177
178 for animation in facts.animations {
179 match animation.kind {
180 ParsedAnimationFactKind::KeyframesDeclaration => keyframe_names.push(animation.name),
181 ParsedAnimationFactKind::AnimationNameReference => {
182 animation_reference_names.push(animation.name);
183 }
184 }
185 }
186
187 for value in facts.css_module_values {
188 match value.kind {
189 ParsedCssModuleValueFactKind::Definition => {
190 css_module_value_definition_names.insert(value.name);
191 }
192 ParsedCssModuleValueFactKind::Reference => {
193 css_module_value_reference_names.insert(value.name);
194 }
195 ParsedCssModuleValueFactKind::ImportSource => {
196 css_module_value_import_sources.insert(value.name);
197 }
198 }
199 }
200
201 for composes in facts.css_module_composes {
202 match composes.kind {
203 ParsedCssModuleComposesFactKind::Target => {
204 css_module_composes_target_names.insert(composes.name);
205 }
206 ParsedCssModuleComposesFactKind::ImportSource => {
207 css_module_composes_import_sources.insert(composes.name);
208 }
209 }
210 }
211
212 for icss in facts.icss {
213 match icss.kind {
214 ParsedIcssFactKind::ExportName => {
215 icss_export_names.insert(icss.name);
216 }
217 ParsedIcssFactKind::ImportLocalName => {
218 icss_import_local_names.insert(icss.name);
219 }
220 ParsedIcssFactKind::ImportRemoteName => {
221 icss_import_remote_names.insert(icss.name);
222 }
223 ParsedIcssFactKind::ImportSource => {
224 icss_import_sources.insert(icss.name);
225 }
226 }
227 }
228
229 OmenaQueryOmenaParserStyleFactsV0 {
230 schema_version: "0",
231 product: "omena-query.omena-parser-style-facts",
232 dialect: omena_parser_style_dialect_label(dialect),
233 class_selector_names,
234 id_selector_names,
235 placeholder_selector_names,
236 keyframe_names,
237 animation_reference_names,
238 css_module_value_definition_names: css_module_value_definition_names.into_iter().collect(),
239 css_module_value_reference_names: css_module_value_reference_names.into_iter().collect(),
240 css_module_value_import_sources: css_module_value_import_sources.into_iter().collect(),
241 css_module_value_import_edges: facts
242 .css_module_value_import_edges
243 .into_iter()
244 .map(|edge| OmenaQueryCssModuleValueImportEdgeFactV0 {
245 remote_name: edge.remote_name,
246 local_name: edge.local_name,
247 import_source: edge.import_source,
248 })
249 .collect(),
250 css_module_value_definition_edges: facts
251 .css_module_value_definition_edges
252 .into_iter()
253 .map(|edge| OmenaQueryCssModuleValueDefinitionEdgeFactV0 {
254 definition_name: edge.definition_name,
255 reference_names: edge.reference_names,
256 })
257 .collect(),
258 css_module_composes_target_names: css_module_composes_target_names.into_iter().collect(),
259 css_module_composes_import_sources: css_module_composes_import_sources
260 .into_iter()
261 .collect(),
262 css_module_composes_edges: facts
263 .css_module_composes_edges
264 .into_iter()
265 .map(|edge| OmenaQueryCssModuleComposesEdgeFactV0 {
266 kind: omena_query_css_module_composes_edge_kind_label(edge.kind),
267 owner_selector_names: edge.owner_selector_names,
268 target_names: edge.target_names,
269 import_source: edge.import_source,
270 })
271 .collect(),
272 icss_export_names: icss_export_names.into_iter().collect(),
273 icss_import_local_names: icss_import_local_names.into_iter().collect(),
274 icss_import_remote_names: icss_import_remote_names.into_iter().collect(),
275 icss_import_sources: icss_import_sources.into_iter().collect(),
276 icss_import_edges: facts
277 .icss_import_edges
278 .into_iter()
279 .map(|edge| OmenaQueryIcssImportEdgeFactV0 {
280 local_name: edge.local_name,
281 remote_name: edge.remote_name,
282 import_source: edge.import_source,
283 })
284 .collect(),
285 icss_export_edges: facts
286 .icss_export_edges
287 .into_iter()
288 .map(|edge| OmenaQueryIcssExportEdgeFactV0 {
289 export_name: edge.export_name,
290 reference_names: edge.reference_names,
291 })
292 .collect(),
293 variable_names: variable_names.into_iter().collect(),
294 sass_symbol_declaration_names: sass_symbol_declaration_names.into_iter().collect(),
295 sass_symbol_reference_names: sass_symbol_reference_names.into_iter().collect(),
296 sass_symbol_facts: facts
297 .sass_symbols
298 .into_iter()
299 .map(|symbol| OmenaQuerySassSymbolFactV0 {
300 kind: omena_query_sass_symbol_fact_kind_label(symbol.kind),
301 symbol_kind: symbol.symbol_kind,
302 name: symbol.name,
303 role: symbol.role,
304 namespace: symbol.namespace,
305 })
306 .collect(),
307 sass_symbol_resolution,
308 sass_module_use_sources: sass_module_use_sources.into_iter().collect(),
309 sass_module_forward_sources: sass_module_forward_sources.into_iter().collect(),
310 sass_module_import_sources: sass_module_import_sources.into_iter().collect(),
311 sass_module_edges: facts
312 .sass_module_edges
313 .into_iter()
314 .map(|edge| OmenaQuerySassModuleEdgeFactV0 {
315 kind: omena_query_sass_module_edge_fact_kind_label(edge.kind),
316 source: edge.source,
317 namespace_kind: edge.namespace_kind,
318 namespace: edge.namespace,
319 forward_prefix: edge.forward_prefix,
320 visibility_filter_kind: edge.visibility_filter_kind,
321 visibility_filter_names: edge.visibility_filter_names,
322 })
323 .collect(),
324 custom_property_names: custom_property_names.into_iter().collect(),
325 custom_property_decl_names: custom_property_decl_names.into_iter().collect(),
326 custom_property_ref_names: custom_property_ref_names.into_iter().collect(),
327 at_rule_names: facts
328 .at_rules
329 .into_iter()
330 .map(|at_rule| at_rule.name)
331 .collect(),
332 parser_error_count: facts.error_count,
333 }
334}
335
336pub fn summarize_omena_query_omena_parser_css_modules_intermediate(
337 style_source: &str,
338 dialect: OmenaParserStyleDialect,
339) -> omena_parser::ParserIndexSummaryV0 {
340 omena_parser::summarize_css_modules_intermediate(style_source, dialect)
341}
342
343pub fn summarize_omena_query_omena_parser_lex(
344 style_source: &str,
345 dialect: OmenaParserStyleDialect,
346) -> omena_parser::OmenaParserLexSummaryV0 {
347 omena_parser::summarize_omena_parser_lex(style_source, dialect)
348}
349
350pub(super) fn omena_parser_dialect_for_style_path(style_path: &str) -> OmenaParserStyleDialect {
351 if style_path.ends_with(".sass") {
352 OmenaParserStyleDialect::Sass
353 } else if style_path.ends_with(".scss") {
354 OmenaParserStyleDialect::Scss
355 } else if style_path.ends_with(".less") {
356 OmenaParserStyleDialect::Less
357 } else {
358 OmenaParserStyleDialect::Css
359 }
360}
361
362pub(super) fn omena_parser_style_dialect_label(dialect: OmenaParserStyleDialect) -> &'static str {
363 match dialect {
364 OmenaParserStyleDialect::Css => "css",
365 OmenaParserStyleDialect::Scss => "scss",
366 OmenaParserStyleDialect::Sass => "sass",
367 OmenaParserStyleDialect::Less => "less",
368 }
369}
370
371pub(super) fn omena_query_css_module_composes_edge_kind_label(
372 kind: ParsedCssModuleComposesEdgeKind,
373) -> &'static str {
374 match kind {
375 ParsedCssModuleComposesEdgeKind::Local => "local",
376 ParsedCssModuleComposesEdgeKind::Global => "global",
377 ParsedCssModuleComposesEdgeKind::External => "external",
378 }
379}
380
381pub(super) fn omena_query_sass_symbol_fact_kind_label(
382 kind: ParsedSassSymbolFactKind,
383) -> &'static str {
384 match kind {
385 ParsedSassSymbolFactKind::VariableDeclaration => "sassVariableDeclaration",
386 ParsedSassSymbolFactKind::VariableReference => "sassVariableReference",
387 ParsedSassSymbolFactKind::MixinDeclaration => "sassMixinDeclaration",
388 ParsedSassSymbolFactKind::MixinInclude => "sassMixinInclude",
389 ParsedSassSymbolFactKind::FunctionDeclaration => "sassFunctionDeclaration",
390 ParsedSassSymbolFactKind::FunctionCall => "sassFunctionCall",
391 }
392}
393
394pub(super) fn omena_query_sass_module_edge_fact_kind_label(
395 kind: ParsedSassModuleEdgeFactKind,
396) -> &'static str {
397 match kind {
398 ParsedSassModuleEdgeFactKind::Use => "sassUse",
399 ParsedSassModuleEdgeFactKind::Forward => "sassForward",
400 ParsedSassModuleEdgeFactKind::Import => "sassImport",
401 }
402}
403
404fn summarize_omena_query_sass_symbol_resolution(
405 symbols: &[omena_parser::ParsedSassSymbolFact],
406) -> OmenaQuerySassSymbolResolutionV0 {
407 let mut declaration_by_symbol: BTreeMap<
408 (&'static str, Option<String>, String),
409 (usize, &'static str),
410 > = BTreeMap::new();
411 let mut declaration_count = 0usize;
412 let mut reference_count = 0usize;
413 let mut edges = Vec::new();
414
415 for (source_order, symbol) in symbols.iter().enumerate() {
416 let kind = omena_query_sass_symbol_fact_kind_label(symbol.kind);
417 if omena_query_sass_symbol_fact_kind_is_declaration(symbol.kind) {
418 declaration_count += 1;
419 declaration_by_symbol.insert(
420 (
421 symbol.symbol_kind,
422 symbol.namespace.clone(),
423 symbol.name.clone(),
424 ),
425 (source_order, kind),
426 );
427 continue;
428 }
429 if !omena_query_sass_symbol_fact_kind_is_reference(symbol.kind) {
430 continue;
431 }
432
433 reference_count += 1;
434 let declaration = declaration_by_symbol.get(&(
435 symbol.symbol_kind,
436 symbol.namespace.clone(),
437 symbol.name.clone(),
438 ));
439 edges.push(OmenaQuerySassSymbolResolutionEdgeV0 {
440 symbol_kind: symbol.symbol_kind,
441 name: symbol.name.clone(),
442 namespace: symbol.namespace.clone(),
443 reference_kind: kind,
444 reference_role: symbol.role,
445 reference_source_order: source_order,
446 declaration_kind: declaration.map(|(_, declaration_kind)| *declaration_kind),
447 declaration_source_order: declaration.map(|(declaration_order, _)| *declaration_order),
448 status: if declaration.is_some() {
449 "resolved"
450 } else {
451 "unresolved"
452 },
453 });
454 }
455
456 let resolved_reference_count = edges
457 .iter()
458 .filter(|edge| edge.status == "resolved")
459 .count();
460 OmenaQuerySassSymbolResolutionV0 {
461 schema_version: "0",
462 product: "omena-query.sass-symbol-same-file-resolution",
463 resolution_scope: "same-file",
464 declaration_count,
465 reference_count,
466 resolved_reference_count,
467 unresolved_reference_count: reference_count.saturating_sub(resolved_reference_count),
468 edges,
469 capabilities: OmenaQuerySassSymbolResolutionCapabilitiesV0 {
470 same_file_lexical_resolution_ready: true,
471 declaration_before_reference_ready: true,
472 unresolved_reference_reporting_ready: true,
473 cross_file_module_resolution_ready: false,
474 },
475 }
476}
477
478pub(super) fn omena_query_sass_symbol_fact_kind_is_declaration(
479 kind: ParsedSassSymbolFactKind,
480) -> bool {
481 matches!(
482 kind,
483 ParsedSassSymbolFactKind::VariableDeclaration
484 | ParsedSassSymbolFactKind::MixinDeclaration
485 | ParsedSassSymbolFactKind::FunctionDeclaration
486 )
487}
488
489pub(super) fn omena_query_sass_symbol_fact_kind_is_reference(
490 kind: ParsedSassSymbolFactKind,
491) -> bool {
492 matches!(
493 kind,
494 ParsedSassSymbolFactKind::VariableReference
495 | ParsedSassSymbolFactKind::MixinInclude
496 | ParsedSassSymbolFactKind::FunctionCall
497 )
498}