1use super::*;
2use omena_cascade::SupportsTargetCapabilityV0;
3use omena_parser::{
4 ClosedWorldBundleBuildErrorV0, ClosedWorldBundleV0, ClosedWorldComposesScanStateV0,
5 ClosedWorldModuleMetadataV0, ClosedWorldSourcePrecisionSummaryV0, OpenWorldSnapshotV0,
6};
7#[cfg(test)]
8use omena_query_transform_runner::{
9 BundleResolutionAuthorityV0, LinkedEmissionModuleRegionV0, LinkedEmissionOrderEntryRegionV0,
10 TransformBundleModuleInputV0, link_omena_transform_bundle_modules, link_resolved_bundle,
11 materialize_omena_transform_bundle_linked_stylesheet,
12};
13use omena_query_transform_runner::{
14 CssModuleTokenOwnershipCensusV0, TransformClassNameRewriteV0,
15 TransformCssModuleComposesResolutionV0, TransformModuleCssModuleContextV0,
16 transform_pass_requires_closed_world_bundle, transform_pass_sort_ordinal,
17};
18#[allow(deprecated)]
19use omena_query_transform_runner::{
20 EmissionOrderingPolicyV0, InstanceReachabilityDerivationV0, LinkedEmissionArtifactV0,
21 LinkedStylesheetWithEmissionItemsV0, TransformBundleDependencyResolutionV0,
22 TransformBundleEdgeKind, TransformBundleEmissionAdmissionV0,
23 TransformBundleEmissionItemProjectionV0, TransformBundleInstanceReachabilityInputV0,
24 TransformBundleLinkErrorV0, TransformBundleLinkOptionsV0, TransformBundleLinkerProjectionV0,
25 TransformBundleParsedModuleInputV0, TransformBundleReachabilityAnalysisV0,
26 TransformBundleReachabilityUnanalyzedCauseV0, TransformBundleResolvedDependencyV0,
27 TransformBundleSemanticReachabilityInputV0, TransformBundleTransformedModuleV0,
28 TransformModuleQualifiedExecutionErrorV0, bundle_edge_is_module_dependency,
29 classify_transform_reachability_precision,
30 evaluate_omena_transform_bundle_projection_emission_admission_with_resolved_dependencies_and_options,
31 execute_transform_passes_on_module_with_dialect_context_policy_and_closed_world_bundle_and_retained_class_names,
32 link_omena_transform_bundle_projection_with_resolved_dependencies_and_options,
33 materialize_omena_transform_bundle_linked_stylesheet_with_emission_items,
34 normalize_omena_transform_bundle_path,
35 project_omena_transform_bundle_linker_and_emission_items_from_parsed_modules_with_instance_reachability,
36 project_omena_transform_bundle_linker_inputs_from_parsed_modules,
37 rewrite_omena_transform_bundle_asset_urls_in_source,
38};
39use omena_sif::normalize_omena_sif_location_spelling_v1;
40use std::path::{Path, PathBuf};
41
42use super::parser_facade::{
43 lex_omena_query_omena_parser_style_source, omena_parser_dialect_for_style_path,
44 parse_omena_query_omena_parser_style_source,
45};
46
47#[cfg(test)]
48mod carrier_hygiene_assertions;
49mod context;
50mod css_modules;
51mod token_integrity;
52pub(super) use css_modules::{
53 derive_class_name_rewrites_for_module_instance, module_instance_key_relative_to_root,
54};
55mod design_tokens;
56mod imports;
57mod static_stylesheet;
58
59use context::TransformResolutionContext;
60pub use context::{
61 derive_omena_query_module_reachability_from_engine_input,
62 summarize_omena_query_transform_context_from_engine_input,
63};
64
65use context::{
66 css_identifier_names_match, dedupe_custom_property_names,
67 derive_omena_query_transform_context_from_engine_input, find_target_style_source,
68 merge_target_options_transform_context, merge_transform_context,
69 summarize_omena_query_transform_context_from_sources_with_resolution_context,
70};
71use imports::resolve_import_inline_replacement_for_transform_context;
72use static_stylesheet::derive_static_scss_module_configurable_variable_names_for_transform_context;
73
74pub(super) struct StaticScssModuleResolutionConfigurationEvidence {
75 pub(super) configuration_signature: String,
76 pub(super) configuration_variable_count: usize,
77 pub(super) configuration_variable_names: Vec<String>,
78 pub(super) module_instance_identity_key: Option<String>,
79}
80
81pub(super) fn derive_static_scss_module_resolution_configuration_evidence(
82 style_source: &str,
83 edge_kind: &str,
84 rule_ordinal: usize,
85 resolved_style_path: Option<&str>,
86) -> StaticScssModuleResolutionConfigurationEvidence {
87 let at_keyword = match edge_kind {
88 "sassUse" => Some("@use"),
89 "sassForward" => Some("@forward"),
90 _ => None,
91 };
92 let variable_overrides = match at_keyword {
93 Some("@forward") => {
94 omena_semantic::derive_sass_module_forward_variable_override_values_at_ordinal(
95 style_source,
96 rule_ordinal,
97 )
98 }
99 Some(at_keyword) => omena_semantic::derive_sass_module_rule_variable_overrides_at_ordinal(
100 style_source,
101 at_keyword,
102 rule_ordinal,
103 ),
104 None => BTreeMap::new(),
105 };
106 let module_instance_identity_key =
107 at_keyword
108 .and(resolved_style_path)
109 .map(|resolved_style_path| {
110 omena_semantic::summarize_sass_module_instance_identity_key(
111 resolved_style_path,
112 &variable_overrides,
113 )
114 });
115
116 StaticScssModuleResolutionConfigurationEvidence {
117 configuration_signature: omena_semantic::summarize_sass_module_configuration_signature(
118 &variable_overrides,
119 ),
120 configuration_variable_count: variable_overrides.len(),
121 configuration_variable_names: variable_overrides.keys().cloned().collect(),
122 module_instance_identity_key,
123 }
124}
125
126pub(super) fn derive_static_scss_module_configurable_variable_names_for_resolution(
127 style_path: &str,
128 style_source: &str,
129 available_style_paths: &BTreeSet<&str>,
130 source_by_path: &BTreeMap<String, String>,
131 package_manifests: &[OmenaQueryStylePackageManifestV0],
132 bundler_path_mappings: &[OmenaResolverBundlerPathAliasMappingV0],
133 tsconfig_path_mappings: &[OmenaResolverTsconfigPathMappingV0],
134) -> BTreeSet<String> {
135 derive_static_scss_module_configurable_variable_names_for_transform_context(
136 style_path,
137 style_source,
138 available_style_paths,
139 source_by_path,
140 TransformResolutionContext {
141 package_manifests,
142 bundler_path_mappings,
143 tsconfig_path_mappings,
144 disk_style_path_identities: &[],
145 resolver_identity_index: None,
146 },
147 )
148}
149
150pub fn summarize_omena_query_transform_plan_from_source(
151 style_path: &str,
152 style_source: &str,
153 target_label: &str,
154 target_support: OmenaQueryTargetFeatureSupportV0,
155 target_options: OmenaQueryTargetTransformOptionsV0,
156 print_options: OmenaQueryTransformPrintOptionsV0,
157) -> OmenaQueryTransformPlanSummaryV0 {
158 summarize_omena_query_transform_plan_from_source_with_context(
159 style_path,
160 style_source,
161 target_label,
162 target_support,
163 target_options,
164 print_options,
165 &TransformExecutionContextV0::default(),
166 )
167}
168
169pub fn summarize_omena_query_transform_plan_from_source_with_context(
170 style_path: &str,
171 style_source: &str,
172 target_label: &str,
173 target_support: OmenaQueryTargetFeatureSupportV0,
174 target_options: OmenaQueryTargetTransformOptionsV0,
175 print_options: OmenaQueryTransformPrintOptionsV0,
176 context: &TransformExecutionContextV0,
177) -> OmenaQueryTransformPlanSummaryV0 {
178 let dialect = omena_parser_dialect_for_style_path(style_path);
179 let bundle = summarize_omena_transform_bundle_from_source(style_path, style_source, dialect);
180 let target = plan_target_transforms(target_label, target_support, target_options);
181 let mut execution_context = merge_target_options_transform_context(context, target_options);
182 execution_context.supports_target_capability = Some(
183 supports_target_capability_from_feature_support(target_support),
184 );
185 summarize_omena_query_transform_plan_from_parts(TransformPlanPartsV0 {
186 style_path,
187 style_source,
188 dialect,
189 bundle,
190 target,
191 target_query: None,
192 print_options,
193 context: &execution_context,
194 })
195}
196
197pub fn summarize_omena_query_transform_plan_from_target_query(
198 style_path: &str,
199 style_source: &str,
200 target_query: &str,
201 target_options: OmenaQueryTargetTransformOptionsV0,
202 print_options: OmenaQueryTransformPrintOptionsV0,
203) -> OmenaQueryTransformPlanSummaryV0 {
204 summarize_omena_query_transform_plan_from_target_query_with_context(
205 style_path,
206 style_source,
207 target_query,
208 target_options,
209 print_options,
210 &TransformExecutionContextV0::default(),
211 )
212}
213
214pub fn summarize_omena_query_transform_plan_from_target_query_with_context(
215 style_path: &str,
216 style_source: &str,
217 target_query: &str,
218 target_options: OmenaQueryTargetTransformOptionsV0,
219 print_options: OmenaQueryTransformPrintOptionsV0,
220 context: &TransformExecutionContextV0,
221) -> OmenaQueryTransformPlanSummaryV0 {
222 let dialect = omena_parser_dialect_for_style_path(style_path);
223 let bundle = summarize_omena_transform_bundle_from_source(style_path, style_source, dialect);
224 let target_query_plan = plan_target_transforms_from_query(target_query, target_options);
225 let vendor_prefix_policy = target_query_plan.vendor_prefix_policy;
226 let supports_target_capability =
227 supports_target_capability_from_feature_support(target_query_plan.support);
228 let target = target_query_plan.transform_plan.clone();
229 let mut execution_context = merge_target_options_transform_context(context, target_options);
230 execution_context.vendor_prefix_policy = vendor_prefix_policy;
231 execution_context.supports_target_capability = Some(supports_target_capability);
232 summarize_omena_query_transform_plan_from_parts(TransformPlanPartsV0 {
233 style_path,
234 style_source,
235 dialect,
236 bundle,
237 target,
238 target_query: Some(target_query_plan),
239 print_options,
240 context: &execution_context,
241 })
242}
243
244struct TransformPlanPartsV0<'a> {
245 style_path: &'a str,
246 style_source: &'a str,
247 dialect: OmenaParserStyleDialect,
248 bundle: TransformBundleSourceSummaryV0,
249 target: TransformTargetPlanV0,
250 target_query: Option<OmenaQueryTransformTargetQueryPlanV0>,
251 print_options: OmenaQueryTransformPrintOptionsV0,
252 context: &'a TransformExecutionContextV0,
253}
254
255pub struct OmenaQueryBundlePlanInputV0<'a> {
256 pub target_style_path: &'a str,
257 pub style_sources: &'a [OmenaQueryStyleSourceInputV0],
258 pub source_map_sources: &'a [OmenaQueryStyleSourceInputV0],
259 pub requested_pass_ids: &'a [String],
260 pub context: &'a TransformExecutionContextV0,
261 pub resolution_inputs: &'a OmenaQueryStyleResolutionInputsV0,
262 pub asset_rewrites: Vec<TransformBundleAssetUrlRewriteSummaryV0>,
263 pub bundle_entry_style_paths: &'a [String],
264}
265
266fn summarize_omena_query_transform_plan_from_parts(
267 parts: TransformPlanPartsV0<'_>,
268) -> OmenaQueryTransformPlanSummaryV0 {
269 let egg = plan_egg_rewrite_passes_for_source(parts.style_source);
270 let custom_property_fixed_point = summarize_static_css_custom_property_fixed_point_from_source(
271 parts.style_source,
272 parts.dialect,
273 );
274
275 let mut combined_passes = Vec::new();
276 extend_passes_from_ids(&parts.bundle.planned_pass_ids, &mut combined_passes);
277 extend_passes_from_ids(&parts.target.planned_pass_ids, &mut combined_passes);
278 extend_passes_from_ids(&egg.planned_pass_ids, &mut combined_passes);
279 combined_passes.push(TransformPassKind::PrintCss);
280 combined_passes.sort_by_key(|pass| transform_pass_sort_ordinal(*pass));
281 combined_passes.dedup();
282
283 let combined_plan = plan_transform_passes(&combined_passes);
284 let semantic_signature = format!(
285 "omena-query-transform:{}:{}",
286 parts.style_path,
287 parts.style_source.len()
288 );
289 let execution = execute_transform_passes_on_source_with_dialect_and_context(
290 parts.style_source,
291 parts.dialect,
292 &combined_passes,
293 parts.context,
294 );
295 let print = print_transform_execution_artifact_with_dialect_and_source(
296 parts.style_path,
297 parts.style_source,
298 parts.dialect,
299 semantic_signature,
300 &combined_passes,
301 parts.print_options,
302 &execution,
303 );
304 let combined_pass_ids = combined_plan.ordered_pass_ids.clone();
305 let egg_witnesses = execute_egg_rewrite_witnesses_for_css_source(
306 parts.style_source,
307 parts.dialect,
308 &execution.output_css,
309 &combined_pass_ids,
310 );
311 let semantic_removal_count = execution.semantic_removals.len();
312 let combined_violated_dag_edge_count = combined_plan.violated_dag_edge_count;
313
314 OmenaQueryTransformPlanSummaryV0 {
315 schema_version: "0",
316 product: "omena-query.transform-plan",
317 style_path: parts.style_path.to_string(),
318 dialect: omena_parser_style_dialect_label(parts.dialect),
319 bundle: parts.bundle,
320 target: parts.target,
321 target_query: parts.target_query,
322 egg,
323 egg_witnesses,
324 custom_property_fixed_point,
325 print,
326 execution,
327 semantic_removal_count,
328 combined_plan,
329 combined_pass_ids,
330 combined_violated_dag_edge_count,
331 ready_surfaces: vec![
332 "transformBundlePlan",
333 "transformTargetPlan",
334 "transformEggPlan",
335 "transformEggExecutionWitnesses",
336 "customPropertyLeastFixedPoint",
337 "transformPrintArtifact",
338 "transformExecutionRuntime",
339 "cascadeProofObligations",
340 "combinedTransformPassPlan",
341 ],
342 }
343}
344
345pub fn run_omena_query_bundle(
346 input: OmenaQueryBundlePlanInputV0<'_>,
347) -> Result<OmenaQueryBundleArtifactV0, String> {
348 run_omena_query_bundle_with_semantic_inputs(input, &[]).map(|result| result.artifact)
349}
350
351pub fn run_omena_query_bundle_with_semantic_inputs(
352 input: OmenaQueryBundlePlanInputV0<'_>,
353 external_sifs: &[OmenaQueryExternalSifInputV0],
354) -> Result<OmenaQueryBundleResultV0, String> {
355 run_omena_query_bundle_with_semantic_inputs_and_options(
356 input,
357 external_sifs,
358 &OmenaQueryConsumerBuildOptionsV0::default(),
359 )
360}
361
362pub fn run_omena_query_bundle_with_semantic_inputs_and_options(
363 input: OmenaQueryBundlePlanInputV0<'_>,
364 external_sifs: &[OmenaQueryExternalSifInputV0],
365 options: &OmenaQueryConsumerBuildOptionsV0,
366) -> Result<OmenaQueryBundleResultV0, String> {
367 run_omena_query_bundle_with_execution_scope_evidence_and_options(input, external_sifs, options)
368 .map(|result| result.bundle_result)
369}
370
371pub fn run_omena_query_bundle_with_token_ownership_census_and_options(
372 input: OmenaQueryBundlePlanInputV0<'_>,
373 external_sifs: &[OmenaQueryExternalSifInputV0],
374 options: &OmenaQueryConsumerBuildOptionsV0,
375) -> Result<OmenaQueryBundleTokenOwnershipResultV0, String> {
376 let run = run_omena_query_bundle_with_optional_module_reachability(
377 input,
378 external_sifs,
379 options,
380 &[],
381 None,
382 None,
383 )?;
384 Ok(OmenaQueryBundleTokenOwnershipResultV0::new(
385 run.bundle_result,
386 run.css_module_token_ownership_census,
387 ))
388}
389
390pub fn run_omena_query_bundle_with_execution_scope_evidence_and_options(
391 input: OmenaQueryBundlePlanInputV0<'_>,
392 external_sifs: &[OmenaQueryExternalSifInputV0],
393 options: &OmenaQueryConsumerBuildOptionsV0,
394) -> Result<OmenaQueryBundleExecutionScopeResultV0, String> {
395 let run = run_omena_query_bundle_with_optional_module_reachability(
396 input,
397 external_sifs,
398 options,
399 &[],
400 None,
401 None,
402 )?;
403 Ok(OmenaQueryBundleExecutionScopeResultV0 {
404 bundle_result: run.bundle_result,
405 execution_scope: run.execution_scope,
406 reachability_attribution: None,
407 })
408}
409
410pub fn run_omena_query_bundle_with_module_css_module_contexts_and_options(
411 input: OmenaQueryBundlePlanInputV0<'_>,
412 external_sifs: &[OmenaQueryExternalSifInputV0],
413 options: &OmenaQueryConsumerBuildOptionsV0,
414 workspace_root: &str,
415 module_css_module_contexts: &[TransformModuleCssModuleContextV0],
416) -> Result<OmenaQueryBundleExecutionScopeResultV0, String> {
417 let run = run_omena_query_bundle_with_optional_module_reachability(
418 input,
419 external_sifs,
420 options,
421 module_css_module_contexts,
422 Some(workspace_root),
423 None,
424 )?;
425 Ok(OmenaQueryBundleExecutionScopeResultV0 {
426 bundle_result: run.bundle_result,
427 execution_scope: run.execution_scope,
428 reachability_attribution: None,
429 })
430}
431
432pub fn run_omena_query_bundle_with_module_reachability_and_options(
433 input: OmenaQueryBundlePlanInputV0<'_>,
434 external_sifs: &[OmenaQueryExternalSifInputV0],
435 options: &OmenaQueryConsumerBuildOptionsV0,
436 module_reachability: &OmenaQueryEngineInputModuleReachabilityV0,
437) -> Result<OmenaQueryModuleAttributedBundleResultV0, String> {
438 let result =
439 run_omena_query_bundle_with_module_reachability_and_execution_scope_evidence_and_options(
440 input,
441 external_sifs,
442 options,
443 module_reachability,
444 )?;
445 let attribution = result.reachability_attribution.ok_or_else(|| {
446 "module reachability run did not retain its attribution report".to_string()
447 })?;
448 Ok(OmenaQueryModuleAttributedBundleResultV0::new(
449 result.bundle_result,
450 attribution,
451 ))
452}
453
454pub fn run_omena_query_bundle_with_module_reachability_and_execution_scope_evidence_and_options(
455 input: OmenaQueryBundlePlanInputV0<'_>,
456 external_sifs: &[OmenaQueryExternalSifInputV0],
457 options: &OmenaQueryConsumerBuildOptionsV0,
458 module_reachability: &OmenaQueryEngineInputModuleReachabilityV0,
459) -> Result<OmenaQueryBundleExecutionScopeResultV0, String> {
460 if find_target_style_source(input.target_style_path, input.style_sources).is_none() {
461 return Err(format!(
462 "module-attributed bundle target style path {:?} was not found in workspace style sources",
463 input.target_style_path
464 ));
465 }
466 let mut flat_context =
467 merge_transform_context(input.context.clone(), module_reachability.context());
468 flat_context
469 .reachable_class_names
470 .extend(module_reachability.projected_class_names().iter().cloned());
471 flat_context.reachable_class_names.sort();
472 flat_context.reachable_class_names.dedup();
473 let style_paths = input
474 .style_sources
475 .iter()
476 .map(|source| source.style_path.as_str())
477 .collect::<Vec<_>>();
478 let flat_class_names = module_reachability.flat_class_names_for_style_paths(
479 style_paths.iter().copied(),
480 flat_context.reachable_class_names.as_slice(),
481 );
482 let attribution_report = OmenaQueryModuleReachabilityAttributionReportV0::from_style_paths(
483 module_reachability,
484 style_paths.iter().copied(),
485 flat_class_names.as_slice(),
486 );
487 let run = run_omena_query_bundle_with_optional_module_reachability(
488 input,
489 external_sifs,
490 options,
491 &[],
492 None,
493 Some((module_reachability, &attribution_report)),
494 )?;
495 Ok(OmenaQueryBundleExecutionScopeResultV0 {
496 bundle_result: run.bundle_result,
497 execution_scope: run.execution_scope,
498 reachability_attribution: Some(attribution_report),
499 })
500}
501
502struct OmenaQueryBundleExecutionRunV0 {
503 bundle_result: OmenaQueryBundleResultV0,
504 execution_scope: Option<OmenaQueryBundleExecutionScopeEvidenceV0>,
505 css_module_token_ownership_census: CssModuleTokenOwnershipCensusV0,
506}
507
508#[allow(deprecated)]
509fn run_omena_query_bundle_with_optional_module_reachability(
510 input: OmenaQueryBundlePlanInputV0<'_>,
511 external_sifs: &[OmenaQueryExternalSifInputV0],
512 options: &OmenaQueryConsumerBuildOptionsV0,
513 module_css_module_contexts: &[TransformModuleCssModuleContextV0],
514 module_identity_root: Option<&str>,
515 module_reachability: Option<(
516 &OmenaQueryEngineInputModuleReachabilityV0,
517 &OmenaQueryModuleReachabilityAttributionReportV0,
518 )>,
519) -> Result<OmenaQueryBundleExecutionRunV0, String> {
520 let OmenaQueryBundlePlanInputV0 {
521 target_style_path,
522 style_sources,
523 source_map_sources,
524 requested_pass_ids,
525 context,
526 resolution_inputs,
527 asset_rewrites: initial_asset_rewrites,
528 bundle_entry_style_paths,
529 } = input;
530 let mut asset_rewrites: Vec<TransformBundleAssetUrlRewriteSummaryV0> = initial_asset_rewrites;
531 let Some(target_source) = find_target_style_source(target_style_path, style_sources) else {
532 return Err(format!(
533 "target style path {target_style_path:?} was not found in workspace style sources"
534 ));
535 };
536 let supplied_context = context;
537 let attributed_context = module_reachability.map(|(reachability, _)| {
538 merge_transform_context(supplied_context.clone(), reachability.context())
539 });
540 let base_context = attributed_context.as_ref().unwrap_or(supplied_context);
541 let workspace_context = merge_workspace_transform_context_with_fact_entries(
542 target_style_path,
543 style_sources,
544 base_context,
545 TransformResolutionContext::from_resolution_inputs(resolution_inputs),
546 );
547 let context = workspace_context.context;
548 let style_fact_entries = workspace_context.style_fact_entries;
549 let reachability_context = if module_reachability.is_some() {
550 supplied_context
551 } else {
552 &context
553 };
554 let attribution_report = module_reachability.map(|(_, report)| report);
555 let effective_pass_ids = consumer_build_pass_set(requested_pass_ids).effective;
556 let legacy_summary =
557 (options.bundle_emission_path == OmenaQueryBundleEmissionPathV0::ImportInlineLegacy)
558 .then(|| {
559 execute_omena_query_consumer_build_style_sources_with_context_resolution_inputs_and_options(
560 target_style_path,
561 style_sources,
562 requested_pass_ids,
563 &context,
564 resolution_inputs,
565 options,
566 )
567 })
568 .transpose()?;
569 let mut bundle = summarize_omena_transform_bundle_from_source(
570 target_style_path,
571 target_source,
572 omena_parser_dialect_for_style_path(target_style_path),
573 );
574 if style_sources.len() > 1 {
575 populate_workspace_bundle_edges_for_admission_witness(&mut bundle, style_sources);
576 }
577 let source_map_sources = if source_map_sources.is_empty() {
578 style_sources
579 } else {
580 source_map_sources
581 };
582 let code_split_outputs = summarize_omena_query_bundle_code_split_workspace_plan(
583 target_style_path,
584 bundle_entry_style_paths,
585 style_sources,
586 resolution_inputs,
587 )?
588 .outputs;
589 let link_options = TransformBundleLinkOptionsV0::default()
590 .with_emission_ordering_policy(EmissionOrderingPolicyV0::ImportOrderPreserving);
591 let (legacy_open_decision, linked_result) = link_closed_world_stylesheet_for_style_sources(
592 ClosedWorldStylesheetRequestV0 {
593 target_style_path,
594 style_sources,
595 requested_pass_ids: &effective_pass_ids,
596 context: &context,
597 reachability_context,
598 attribution_report,
599 resolution_inputs,
600 external_sifs,
601 source_set_closed: true,
602 },
603 link_options,
604 )
605 .into_parts();
606 let closed_world_outcome = closed_world_outcome_from_link_result(
607 linked_result.clone().map(|linked| linked.linked_stylesheet),
608 &effective_pass_ids,
609 );
610 let closed_world_decision_parity = OmenaQueryClosedWorldDecisionParityV0 {
611 legacy_open_decision,
612 typed_outcome_open: closed_world_outcome.is_open(),
613 equivalent: legacy_open_decision == closed_world_outcome.is_open(),
614 };
615 validate_omena_query_closed_world_decision_parity(&closed_world_decision_parity)?;
616
617 let (
618 execution,
619 linked_materialization,
620 emission_path,
621 mut execution_scope,
622 linked_module_executions,
623 ) = match options.bundle_emission_path {
624 OmenaQueryBundleEmissionPathV0::LinkedOrder => match linked_result.as_ref() {
625 Ok(linked) => {
626 let linked_execution = execute_linked_bundle_modules_with_ownership_reference(
627 linked,
628 target_style_path,
629 style_sources,
630 style_fact_entries.as_slice(),
631 &effective_pass_ids,
632 base_context,
633 module_css_module_contexts,
634 module_identity_root,
635 resolution_inputs,
636 asset_rewrites.as_slice(),
637 options,
638 )?;
639 asset_rewrites.extend_from_slice(&linked_execution.asset_rewrites);
640 let execution_scope = summarize_linked_bundle_execution_scope(&linked_execution)?;
641 (
642 linked_execution.execution,
643 Some(linked_execution.materialization),
644 OmenaQueryBundleEmissionPathV0::LinkedOrder,
645 Some(execution_scope),
646 Some(linked_execution.module_executions),
647 )
648 }
649 Err(error) => return Err(format!("linked bundle emission failed: {error:?}")),
650 },
651 OmenaQueryBundleEmissionPathV0::ImportInlineLegacy => match linked_result.as_ref() {
652 Ok(linked)
653 if linked
654 .linked_stylesheet
655 .module_instances
656 .iter()
657 .any(|instance| {
658 css_modules::style_path_is_css_module_path(instance.module().as_str())
659 }) =>
660 {
661 let linked_execution = execute_linked_bundle_modules_with_ownership_reference(
662 linked,
663 target_style_path,
664 style_sources,
665 style_fact_entries.as_slice(),
666 &effective_pass_ids,
667 base_context,
668 module_css_module_contexts,
669 module_identity_root,
670 resolution_inputs,
671 asset_rewrites.as_slice(),
672 options,
673 )?;
674 asset_rewrites.extend_from_slice(&linked_execution.asset_rewrites);
675 (
676 linked_execution.execution,
677 None,
678 OmenaQueryBundleEmissionPathV0::ImportInlineLegacy,
679 None,
680 Some(linked_execution.module_executions),
681 )
682 }
683 Ok(_) | Err(_) => {
684 let Some(summary) = legacy_summary else {
685 return Err(
686 "legacy bundle emission requires a consumer build summary".to_string()
687 );
688 };
689 (
690 summary.execution,
691 None,
692 OmenaQueryBundleEmissionPathV0::ImportInlineLegacy,
693 None,
694 None,
695 )
696 }
697 },
698 };
699 let source_map_v3 = if let (Some(materialization), Some(module_executions)) = (
700 linked_materialization.as_ref(),
701 linked_module_executions.as_deref(),
702 ) {
703 let (source_map, dispositions) = summarize_omena_query_linked_bundle_source_map_v3(
704 target_style_path,
705 source_map_sources,
706 &execution,
707 materialization,
708 module_executions,
709 )?;
710 if let Some(scope) = execution_scope.as_mut() {
711 scope.source_map_dispositions = dispositions;
712 }
713 source_map
714 } else {
715 summarize_omena_query_consumer_build_source_map_v3_with_resolution_inputs(
716 target_style_path,
717 source_map_sources,
718 &execution,
719 resolution_inputs,
720 )
721 };
722
723 let css_module_token_ownership_census = match linked_result.as_ref() {
724 Ok(linked) => token_integrity::summarize_css_module_token_ownership(
725 target_style_path,
726 style_fact_entries.as_slice(),
727 linked,
728 &context,
729 linked_module_executions.as_deref(),
730 module_identity_root,
731 emission_path,
732 execution.output_css.as_str(),
733 )
734 .unwrap_or_else(|error| {
735 token_integrity::unavailable_css_module_token_ownership_census(emission_path, error)
736 }),
737 Err(error) => token_integrity::unavailable_css_module_token_ownership_census(
738 emission_path,
739 format!(
740 "CSS Modules emitted-token integrity could not attribute the emission plan: {error:?}"
741 ),
742 ),
743 };
744 if options.verification_profile == OmenaQueryBuildVerificationProfileV0::Strict {
745 token_integrity::validate_css_module_token_integrity(&css_module_token_ownership_census)?;
746 }
747
748 let artifact = OmenaQueryBundleArtifactV0 {
749 schema_version: "0",
750 product: "omena-query.bundle-artifact",
751 style_path: target_style_path.to_string(),
752 emission_path,
753 output_css: execution.output_css.clone(),
754 bundle,
755 source_map_v3,
756 code_split_outputs,
757 asset_rewrites,
758 per_pass_provenance: execution.outcomes.clone(),
759 execution,
760 ready_surfaces: vec![
761 "bundleOperationFacade",
762 "transformBundlePlan",
763 "transformExecutionRuntime",
764 "sourceMapV3Serializer",
765 "bundleCodeSplitPlan",
766 "transformPassOutcomeContract",
767 ],
768 };
769 Ok(OmenaQueryBundleExecutionRunV0 {
770 bundle_result: OmenaQueryBundleResultV0 {
771 artifact,
772 closed_world_outcome,
773 closed_world_decision_parity,
774 },
775 execution_scope,
776 css_module_token_ownership_census,
777 })
778}
779
780fn populate_workspace_bundle_edges_for_admission_witness(
781 bundle: &mut TransformBundleSourceSummaryV0,
782 style_sources: &[OmenaQueryStyleSourceInputV0],
783) {
784 let mut edges = Vec::new();
785 for source in style_sources {
786 let summary = summarize_omena_transform_bundle_from_source(
787 source.style_path.as_str(),
788 source.style_source.as_str(),
789 omena_parser_dialect_for_style_path(source.style_path.as_str()),
790 );
791 for edge in summary.bundle_edges {
792 if !edges.contains(&edge) {
793 edges.push(edge);
794 }
795 }
796 }
797 bundle.bundle_edges = edges;
798}
799
800pub fn run_omena_query_bundle_for_style_sources_with_context(
801 target_style_path: &str,
802 style_sources: &[OmenaQueryStyleSourceInputV0],
803 requested_pass_ids: &[String],
804 context: &TransformExecutionContextV0,
805 package_manifests: &[OmenaQueryStylePackageManifestV0],
806 bundle_entry_style_paths: &[String],
807) -> Result<OmenaQueryBundleArtifactV0, String> {
808 run_omena_query_bundle_with_evidence_for_style_sources_with_context(
809 target_style_path,
810 style_sources,
811 requested_pass_ids,
812 context,
813 package_manifests,
814 bundle_entry_style_paths,
815 )
816 .map(|bundle| bundle.artifact)
817}
818
819pub fn run_omena_query_bundle_with_evidence_for_style_sources_with_context(
820 target_style_path: &str,
821 style_sources: &[OmenaQueryStyleSourceInputV0],
822 requested_pass_ids: &[String],
823 context: &TransformExecutionContextV0,
824 package_manifests: &[OmenaQueryStylePackageManifestV0],
825 bundle_entry_style_paths: &[String],
826) -> Result<OmenaQueryBundleWithEvidenceV0, String> {
827 let resolution_inputs = resolution_inputs_for_transform_style_sources(
828 target_style_path,
829 style_sources,
830 package_manifests,
831 );
832 let result = run_omena_query_bundle_with_semantic_inputs(
833 OmenaQueryBundlePlanInputV0 {
834 target_style_path,
835 style_sources,
836 source_map_sources: style_sources,
837 requested_pass_ids,
838 context,
839 resolution_inputs: &resolution_inputs,
840 asset_rewrites: Vec::new(),
841 bundle_entry_style_paths,
842 },
843 &[],
844 )?;
845 let evidence = summarize_omena_query_bundle_evidence(&result);
846 Ok(OmenaQueryBundleWithEvidenceV0 {
847 artifact: result.artifact,
848 closed_world_outcome: result.closed_world_outcome,
849 closed_world_decision_parity: result.closed_world_decision_parity,
850 evidence,
851 })
852}
853
854pub fn run_omena_query_bundle_with_execution_scope_for_style_sources_with_context_and_options(
855 target_style_path: &str,
856 style_sources: &[OmenaQueryStyleSourceInputV0],
857 requested_pass_ids: &[String],
858 context: &TransformExecutionContextV0,
859 package_manifests: &[OmenaQueryStylePackageManifestV0],
860 bundle_entry_style_paths: &[String],
861 options: &OmenaQueryConsumerBuildOptionsV0,
862) -> Result<OmenaQueryBundleExecutionScopeResultV0, String> {
863 let resolution_inputs = resolution_inputs_for_transform_style_sources(
864 target_style_path,
865 style_sources,
866 package_manifests,
867 );
868 run_omena_query_bundle_with_execution_scope_evidence_and_options(
869 OmenaQueryBundlePlanInputV0 {
870 target_style_path,
871 style_sources,
872 source_map_sources: style_sources,
873 requested_pass_ids,
874 context,
875 resolution_inputs: &resolution_inputs,
876 asset_rewrites: Vec::new(),
877 bundle_entry_style_paths,
878 },
879 &[],
880 options,
881 )
882}
883
884#[allow(clippy::too_many_arguments)]
885pub fn run_omena_query_bundle_with_module_css_module_contexts_for_style_sources_with_context_and_options(
886 workspace_root: &str,
887 target_style_path: &str,
888 style_sources: &[OmenaQueryStyleSourceInputV0],
889 requested_pass_ids: &[String],
890 context: &TransformExecutionContextV0,
891 package_manifests: &[OmenaQueryStylePackageManifestV0],
892 bundle_entry_style_paths: &[String],
893 module_css_module_contexts: &[TransformModuleCssModuleContextV0],
894 options: &OmenaQueryConsumerBuildOptionsV0,
895) -> Result<OmenaQueryBundleExecutionScopeResultV0, String> {
896 let resolution_inputs = resolution_inputs_for_transform_style_sources(
897 target_style_path,
898 style_sources,
899 package_manifests,
900 );
901 run_omena_query_bundle_with_module_css_module_contexts_and_options(
902 OmenaQueryBundlePlanInputV0 {
903 target_style_path,
904 style_sources,
905 source_map_sources: style_sources,
906 requested_pass_ids,
907 context,
908 resolution_inputs: &resolution_inputs,
909 asset_rewrites: Vec::new(),
910 bundle_entry_style_paths,
911 },
912 &[],
913 options,
914 workspace_root,
915 module_css_module_contexts,
916 )
917}
918
919pub fn summarize_omena_query_bundle_evidence(
920 result: &OmenaQueryBundleResultV0,
921) -> OmenaQueryBundleEvidenceManifestV0 {
922 let artifact = &result.artifact;
923 let (outcome_status, reachability, blockers, interface_hashes, source_precision) = match &result
924 .closed_world_outcome
925 {
926 OmenaQueryClosedWorldOutcomeV0::Closed { bundle } => (
927 "closed",
928 Some(OmenaQueryBundleReachabilityEvidenceV0 {
929 guarantee: omena_evidence_graph::GuaranteeKindV0::NotClaimedExactTraversal,
930 interpretation: "resolved-world exact BFS reachability; world incompleteness is represented by blockers",
931 module_instances: bundle.reachability().module_instances().to_vec(),
932 closure_hash: bundle.closure_hash().to_string(),
933 }),
934 Vec::new(),
935 bundle.interface_hashes().entries().to_vec(),
936 bundle.source_precision(),
937 ),
938 OmenaQueryClosedWorldOutcomeV0::Open { blockers } => {
939 ("open", None, blockers.clone(), Vec::new(), None)
940 }
941 };
942 OmenaQueryBundleEvidenceManifestV0 {
943 schema_version: "0",
944 product: "omena-query.bundle-evidence",
945 style_path: artifact.style_path.clone(),
946 outcome_status,
947 reachability,
948 gates: vec![
949 OmenaQueryBundleEvidenceGateV0 {
950 name: "resolvedWorldLink",
951 passed: outcome_status == "closed",
952 },
953 OmenaQueryBundleEvidenceGateV0 {
954 name: "closedWorldAdmission",
955 passed: outcome_status == "closed" && blockers.is_empty(),
956 },
957 OmenaQueryBundleEvidenceGateV0 {
958 name: "closedWorldDecisionParity",
959 passed: result.closed_world_decision_parity.equivalent,
960 },
961 ],
962 blockers,
963 interface_hashes,
964 source_precision,
965 }
966}
967
968pub fn validate_omena_query_closed_world_decision_parity(
969 parity: &OmenaQueryClosedWorldDecisionParityV0,
970) -> Result<(), String> {
971 if parity.equivalent && parity.legacy_open_decision == parity.typed_outcome_open {
972 return Ok(());
973 }
974 Err(format!(
975 "closed-world decision parity mismatch: legacyOpen={}, typedOutcomeOpen={}",
976 parity.legacy_open_decision, parity.typed_outcome_open
977 ))
978}
979
980pub fn execute_omena_query_transform_passes_from_source(
981 style_path: &str,
982 style_source: &str,
983 requested_pass_ids: &[String],
984) -> OmenaQueryTransformExecuteSummaryV0 {
985 execute_omena_query_transform_passes_from_source_with_context(
986 style_path,
987 style_source,
988 requested_pass_ids,
989 &TransformExecutionContextV0::default(),
990 )
991}
992
993pub fn summarize_omena_query_consumer_check_style_source(
994 style_path: &str,
995 style_source: &str,
996) -> OmenaQueryConsumerCheckSummaryV0 {
997 let dialect = omena_parser_dialect_for_style_path(style_path);
998 let parse_result = parse_omena_query_omena_parser_style_source(style_source, dialect);
999 let runtime_index =
1000 omena_semantic::summarize_style_runtime_index_facts_from_source(style_path, style_source);
1001 let (class_selector_count, custom_property_count, keyframe_count, index_ready_surface) =
1002 if let Some(runtime_index) = runtime_index {
1003 (
1004 runtime_index.class_selector_names.len(),
1005 runtime_index.custom_property_names.len(),
1006 runtime_index.keyframe_names.len(),
1007 "semanticRuntimeIndexFacts",
1008 )
1009 } else {
1010 let style_facts = summarize_omena_query_omena_parser_style_facts(style_source, dialect);
1011 (
1012 style_facts.class_selector_names.len(),
1013 style_facts.custom_property_names.len(),
1014 style_facts.keyframe_names.len(),
1015 "parserFactSummary",
1016 )
1017 };
1018
1019 OmenaQueryConsumerCheckSummaryV0 {
1020 schema_version: "0",
1021 product: "omena-query.consumer-check-style-source",
1022 style_path: style_path.to_string(),
1023 dialect: omena_parser_style_dialect_label(dialect),
1024 token_count: parse_result.token_count(),
1025 parser_error_count: parse_result.errors().len(),
1026 class_selector_count,
1027 custom_property_count,
1028 keyframe_count,
1029 ready_surfaces: vec![
1030 "consumerCheckFacade",
1031 index_ready_surface,
1032 "styleDocumentDiagnostics",
1033 ],
1034 }
1035}
1036
1037pub fn execute_omena_query_consumer_build_style_source(
1038 style_path: &str,
1039 style_source: &str,
1040 requested_pass_ids: &[String],
1041) -> OmenaQueryConsumerBuildSummaryV0 {
1042 execute_omena_query_consumer_build_style_source_with_context_and_options(
1043 style_path,
1044 style_source,
1045 requested_pass_ids,
1046 &TransformExecutionContextV0::default(),
1047 &OmenaQueryConsumerBuildOptionsV0::default(),
1048 )
1049}
1050
1051pub fn execute_omena_query_consumer_build_style_source_with_context(
1052 style_path: &str,
1053 style_source: &str,
1054 requested_pass_ids: &[String],
1055 context: &TransformExecutionContextV0,
1056) -> OmenaQueryConsumerBuildSummaryV0 {
1057 execute_omena_query_consumer_build_style_source_with_context_and_options(
1058 style_path,
1059 style_source,
1060 requested_pass_ids,
1061 context,
1062 &OmenaQueryConsumerBuildOptionsV0::default(),
1063 )
1064}
1065
1066pub fn execute_omena_query_consumer_build_style_source_with_context_and_options(
1067 style_path: &str,
1068 style_source: &str,
1069 requested_pass_ids: &[String],
1070 context: &TransformExecutionContextV0,
1071 options: &OmenaQueryConsumerBuildOptionsV0,
1072) -> OmenaQueryConsumerBuildSummaryV0 {
1073 execute_omena_query_consumer_build_style_source_with_context_and_reachability_precision(
1074 style_path,
1075 style_source,
1076 requested_pass_ids,
1077 context,
1078 None,
1079 false,
1080 options,
1081 )
1082}
1083
1084fn execute_omena_query_consumer_build_style_source_with_context_and_reachability_precision(
1085 style_path: &str,
1086 style_source: &str,
1087 requested_pass_ids: &[String],
1088 context: &TransformExecutionContextV0,
1089 reachability_precision: Option<FactPrecision>,
1090 closed_set_enumeration_candidate: bool,
1091 options: &OmenaQueryConsumerBuildOptionsV0,
1092) -> OmenaQueryConsumerBuildSummaryV0 {
1093 let context = merge_single_source_transform_context(style_path, style_source, context);
1094 let pass_set = consumer_build_pass_set(requested_pass_ids);
1095 let closed_world_outcome =
1096 pass_ids_require_closed_world_bundle(&pass_set.effective).then(|| {
1097 build_closed_world_outcome_for_single_style_source_context(
1098 style_path,
1099 style_source,
1100 &pass_set.effective,
1101 &context,
1102 )
1103 });
1104 if let Some(closed_world_bundle) = closed_world_outcome
1105 .as_ref()
1106 .and_then(OmenaQueryClosedWorldOutcomeV0::bundle)
1107 {
1108 let reachability_precision = closed_world_bound_reachability_precision(
1109 &context,
1110 closed_world_bundle,
1111 reachability_precision,
1112 closed_set_enumeration_candidate,
1113 );
1114 return execute_omena_query_consumer_build_style_source_with_context_and_closed_world_bundle(
1115 style_path,
1116 style_source,
1117 &pass_set,
1118 &context,
1119 closed_world_bundle,
1120 reachability_precision,
1121 options,
1122 );
1123 }
1124
1125 execute_omena_query_consumer_build_style_source_with_open_world_context(
1126 style_path,
1127 style_source,
1128 &pass_set,
1129 &context,
1130 options,
1131 )
1132}
1133
1134struct ConsumerBuildPassSetV0 {
1135 requested: Vec<String>,
1136 effective: Vec<String>,
1137}
1138
1139fn consumer_build_pass_set(requested_pass_ids: &[String]) -> ConsumerBuildPassSetV0 {
1140 ConsumerBuildPassSetV0 {
1141 requested: requested_pass_ids.to_vec(),
1142 effective: compute_effective_pass_ids(requested_pass_ids),
1143 }
1144}
1145
1146fn compute_effective_pass_ids(requested_pass_ids: &[String]) -> Vec<String> {
1147 if !requested_pass_ids.is_empty() {
1148 return requested_pass_ids.to_vec();
1149 }
1150
1151 all_transform_pass_kinds()
1152 .into_iter()
1153 .filter(|pass| {
1154 *pass != TransformPassKind::NativeCssStaticEval
1155 && !transform_pass_requires_closed_world_bundle(*pass)
1156 })
1157 .map(|pass| pass.id().to_string())
1158 .collect()
1159}
1160
1161fn execution_policy_for_build_options(
1162 options: &OmenaQueryConsumerBuildOptionsV0,
1163) -> TransformExecutionPolicyV0 {
1164 match options.verification_profile {
1165 OmenaQueryBuildVerificationProfileV0::Descriptive => TransformExecutionPolicyV0::default(),
1166 OmenaQueryBuildVerificationProfileV0::Strict => TransformExecutionPolicyV0::for_profile(
1167 omena_query_transform_runner::STRICT_VERIFICATION_BUILD_PROFILE_ID_V0,
1168 )
1169 .unwrap_or_default(),
1170 }
1171}
1172
1173fn execute_omena_query_consumer_build_style_source_with_open_world_context(
1174 style_path: &str,
1175 style_source: &str,
1176 pass_set: &ConsumerBuildPassSetV0,
1177 context: &TransformExecutionContextV0,
1178 options: &OmenaQueryConsumerBuildOptionsV0,
1179) -> OmenaQueryConsumerBuildSummaryV0 {
1180 let execution_summary =
1181 execute_omena_query_transform_passes_from_source_with_open_world_context(
1182 style_path,
1183 style_source,
1184 &pass_set.effective,
1185 context,
1186 &execution_policy_for_build_options(options),
1187 );
1188 let open_world_snapshot = open_world_snapshot_for_closed_world_passes(&pass_set.effective);
1189 let ready_surfaces = consumer_build_ready_surfaces_with_open_world_snapshot(
1190 open_world_snapshot.as_ref(),
1191 vec![
1192 "consumerBuildFacade",
1193 "singleSourceTransformContextProducer",
1194 "transformExecutionRuntime",
1195 "transformPassOutcomeContract",
1196 ],
1197 );
1198
1199 OmenaQueryConsumerBuildSummaryV0 {
1200 schema_version: "0",
1201 product: "omena-query.consumer-build-style-source",
1202 style_path: style_path.to_string(),
1203 dialect: omena_parser_style_dialect_label(omena_parser_dialect_for_style_path(style_path)),
1204 requested_pass_ids: pass_set.requested.clone(),
1205 effective_pass_ids: pass_set.effective.clone(),
1206 target_query: None,
1207 unknown_pass_ids: execution_summary.unknown_pass_ids,
1208 semantic_removal_count: execution_summary.semantic_removal_count,
1209 execution: execution_summary.execution,
1210 bundle: None,
1211 bundle_emission_path: None,
1212 source_map_v3: None,
1213 open_world_snapshot,
1214 ready_surfaces,
1215 }
1216}
1217
1218fn execute_omena_query_consumer_build_style_source_with_context_and_closed_world_bundle(
1219 style_path: &str,
1220 style_source: &str,
1221 pass_set: &ConsumerBuildPassSetV0,
1222 context: &TransformExecutionContextV0,
1223 closed_world_bundle: &ClosedWorldBundleV0,
1224 reachability_precision: FactPrecision,
1225 options: &OmenaQueryConsumerBuildOptionsV0,
1226) -> OmenaQueryConsumerBuildSummaryV0 {
1227 let context = merge_single_source_transform_context(style_path, style_source, context);
1228 let execution_summary =
1229 execute_omena_query_transform_passes_from_source_with_context_and_closed_world_bundle(
1230 style_path,
1231 style_source,
1232 &pass_set.effective,
1233 &context,
1234 closed_world_bundle,
1235 reachability_precision,
1236 &execution_policy_for_build_options(options),
1237 );
1238
1239 OmenaQueryConsumerBuildSummaryV0 {
1240 schema_version: "0",
1241 product: "omena-query.consumer-build-style-source",
1242 style_path: style_path.to_string(),
1243 dialect: omena_parser_style_dialect_label(omena_parser_dialect_for_style_path(style_path)),
1244 requested_pass_ids: pass_set.requested.clone(),
1245 effective_pass_ids: pass_set.effective.clone(),
1246 target_query: None,
1247 unknown_pass_ids: execution_summary.unknown_pass_ids,
1248 semantic_removal_count: execution_summary.semantic_removal_count,
1249 execution: execution_summary.execution,
1250 bundle: None,
1251 bundle_emission_path: None,
1252 source_map_v3: None,
1253 open_world_snapshot: None,
1254 ready_surfaces: vec![
1255 "consumerBuildFacade",
1256 "singleSourceTransformContextProducer",
1257 "closedWorldBundle",
1258 "transformExecutionRuntime",
1259 "transformPassOutcomeContract",
1260 ],
1261 }
1262}
1263
1264struct ModuleQualifiedExecutionInputsV0<'a> {
1265 closed_world_bundle: &'a ClosedWorldBundleV0,
1266 module_instance: &'a omena_parser::ModuleInstanceKeyV0,
1267 ownership_module_instance: &'a omena_parser::ModuleInstanceKeyV0,
1268 reachability_precision: FactPrecision,
1269 retained_class_names: &'a [String],
1270 token_ownership_census: Option<&'a CssModuleTokenOwnershipCensusV0>,
1271}
1272
1273fn execute_omena_query_consumer_build_style_module_with_context_and_closed_world_bundle(
1274 style_path: &str,
1275 style_source: &str,
1276 pass_set: &ConsumerBuildPassSetV0,
1277 context: &TransformExecutionContextV0,
1278 execution_inputs: ModuleQualifiedExecutionInputsV0<'_>,
1279 options: &OmenaQueryConsumerBuildOptionsV0,
1280) -> Result<OmenaQueryConsumerBuildSummaryV0, String> {
1281 let context = merge_single_source_transform_context(style_path, style_source, context);
1282 let execution_policy = execution_policy_for_build_options(options);
1283 let execution_summary =
1284 execute_omena_query_transform_passes_from_module_with_context_and_closed_world_bundle(
1285 style_path,
1286 style_source,
1287 &pass_set.effective,
1288 &context,
1289 execution_inputs,
1290 &execution_policy,
1291 )
1292 .map_err(|error| format!("module-qualified transform execution failed: {error:?}"))?;
1293
1294 Ok(OmenaQueryConsumerBuildSummaryV0 {
1295 schema_version: "0",
1296 product: "omena-query.consumer-build-style-source",
1297 style_path: style_path.to_string(),
1298 dialect: omena_parser_style_dialect_label(omena_parser_dialect_for_style_path(style_path)),
1299 requested_pass_ids: pass_set.requested.clone(),
1300 effective_pass_ids: pass_set.effective.clone(),
1301 target_query: None,
1302 unknown_pass_ids: execution_summary.unknown_pass_ids,
1303 semantic_removal_count: execution_summary.semantic_removal_count,
1304 execution: execution_summary.execution,
1305 bundle: None,
1306 bundle_emission_path: None,
1307 source_map_v3: None,
1308 open_world_snapshot: None,
1309 ready_surfaces: vec![
1310 "consumerBuildFacade",
1311 "singleSourceTransformContextProducer",
1312 "closedWorldBundle",
1313 "moduleQualifiedReachability",
1314 "transformExecutionRuntime",
1315 "transformPassOutcomeContract",
1316 ],
1317 })
1318}
1319
1320pub fn execute_omena_query_consumer_build_style_source_with_engine_input_context(
1321 style_path: &str,
1322 style_source: &str,
1323 requested_pass_ids: &[String],
1324 input: &EngineInputV2,
1325 closed_world_requested: bool,
1326) -> OmenaQueryConsumerBuildSummaryV0 {
1327 let context_derivation = derive_omena_query_transform_context_from_engine_input(
1328 input,
1329 style_path,
1330 closed_world_requested,
1331 );
1332 let mut summary =
1333 execute_omena_query_consumer_build_style_source_with_context_and_reachability_precision(
1334 style_path,
1335 style_source,
1336 requested_pass_ids,
1337 context_derivation.module_reachability.context(),
1338 context_derivation.reachability_precision,
1339 context_derivation.closed_set_enumeration_candidate,
1340 &OmenaQueryConsumerBuildOptionsV0::default(),
1341 );
1342 summary
1343 .ready_surfaces
1344 .push("semanticReachabilityTransformContext");
1345 summary
1346 .ready_surfaces
1347 .push("expressionDomainSelectorProjection");
1348 summary
1349}
1350
1351fn closed_world_bound_reachability_precision(
1352 context: &TransformExecutionContextV0,
1353 closed_world_bundle: &ClosedWorldBundleV0,
1354 open_world_precision: Option<FactPrecision>,
1355 closed_set_enumeration_candidate: bool,
1356) -> FactPrecision {
1357 let fallback = open_world_precision.unwrap_or(FactPrecision::Conservative);
1358 if !closed_set_enumeration_candidate
1359 || !fallback.satisfies(FactPrecision::Conservative)
1360 || context.reachable_class_names.is_empty()
1361 {
1362 return fallback;
1363 }
1364
1365 let closed_world_class_names = closed_world_bundle
1366 .reachability()
1367 .class_names()
1368 .iter()
1369 .map(String::as_str)
1370 .collect::<BTreeSet<_>>();
1371 let enumerated_class_names = context
1372 .reachable_class_names
1373 .iter()
1374 .cloned()
1375 .collect::<BTreeSet<_>>();
1376 if enumerated_class_names
1377 .iter()
1378 .any(|name| !closed_world_class_names.contains(name.as_str()))
1379 {
1380 return fallback;
1381 }
1382
1383 let value = AbstractClassValueV0::FiniteSet {
1384 values: enumerated_class_names.into_iter().collect(),
1385 };
1386 let witness = OmenaAbstractValuePrecisionWitnessV0 {
1387 direction: OmenaAbstractValueCoverageDirectionV0::SupersetOfProducible,
1388 basis: OmenaAbstractValuePrecisionBasisV0::ClosedSetEnumeration,
1389 authority_digest: Some(closed_world_bundle.closure_hash().to_string()),
1390 };
1391 fact_precision_from_class_value_with_witness(&value, Some(&witness))
1392}
1393
1394pub fn execute_omena_query_consumer_build_style_sources_with_context(
1395 target_style_path: &str,
1396 style_sources: &[OmenaQueryStyleSourceInputV0],
1397 requested_pass_ids: &[String],
1398 context: &TransformExecutionContextV0,
1399 package_manifests: &[OmenaQueryStylePackageManifestV0],
1400) -> Result<OmenaQueryConsumerBuildSummaryV0, String> {
1401 execute_omena_query_consumer_build_style_sources_with_context_and_options(
1402 target_style_path,
1403 style_sources,
1404 requested_pass_ids,
1405 context,
1406 package_manifests,
1407 &OmenaQueryConsumerBuildOptionsV0::default(),
1408 )
1409}
1410
1411pub fn execute_omena_query_consumer_build_style_sources_with_context_and_options(
1412 target_style_path: &str,
1413 style_sources: &[OmenaQueryStyleSourceInputV0],
1414 requested_pass_ids: &[String],
1415 context: &TransformExecutionContextV0,
1416 package_manifests: &[OmenaQueryStylePackageManifestV0],
1417 options: &OmenaQueryConsumerBuildOptionsV0,
1418) -> Result<OmenaQueryConsumerBuildSummaryV0, String> {
1419 let resolution_inputs = resolution_inputs_for_transform_style_sources(
1420 target_style_path,
1421 style_sources,
1422 package_manifests,
1423 );
1424 execute_omena_query_consumer_build_style_sources_with_context_resolution_inputs_and_options(
1425 target_style_path,
1426 style_sources,
1427 requested_pass_ids,
1428 context,
1429 &resolution_inputs,
1430 options,
1431 )
1432}
1433
1434pub fn execute_omena_query_consumer_build_style_sources_with_context_and_resolution_inputs(
1435 target_style_path: &str,
1436 style_sources: &[OmenaQueryStyleSourceInputV0],
1437 requested_pass_ids: &[String],
1438 context: &TransformExecutionContextV0,
1439 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
1440) -> Result<OmenaQueryConsumerBuildSummaryV0, String> {
1441 execute_omena_query_consumer_build_style_sources_with_context_resolution_inputs_and_options(
1442 target_style_path,
1443 style_sources,
1444 requested_pass_ids,
1445 context,
1446 resolution_inputs,
1447 &OmenaQueryConsumerBuildOptionsV0::default(),
1448 )
1449}
1450
1451pub fn execute_omena_query_consumer_build_style_sources_with_context_resolution_inputs_and_options(
1452 target_style_path: &str,
1453 style_sources: &[OmenaQueryStyleSourceInputV0],
1454 requested_pass_ids: &[String],
1455 context: &TransformExecutionContextV0,
1456 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
1457 options: &OmenaQueryConsumerBuildOptionsV0,
1458) -> Result<OmenaQueryConsumerBuildSummaryV0, String> {
1459 let Some(target_source) = find_target_style_source(target_style_path, style_sources) else {
1460 return Err(format!(
1461 "target style path {target_style_path:?} was not found in workspace style sources"
1462 ));
1463 };
1464 let context = merge_workspace_transform_context(
1465 target_style_path,
1466 style_sources,
1467 context,
1468 TransformResolutionContext::from_resolution_inputs(resolution_inputs),
1469 );
1470 let pass_set = consumer_build_pass_set(requested_pass_ids);
1471 let closed_world_outcome =
1472 pass_ids_require_closed_world_bundle(&pass_set.effective).then(|| {
1473 build_closed_world_outcome_for_style_sources(ClosedWorldStylesheetRequestV0 {
1474 target_style_path,
1475 style_sources,
1476 requested_pass_ids: &pass_set.effective,
1477 context: &context,
1478 reachability_context: &context,
1479 attribution_report: None,
1480 resolution_inputs,
1481 external_sifs: &[],
1482 source_set_closed: false,
1483 })
1484 });
1485 let mut summary = if let Some(closed_world_bundle) = closed_world_outcome
1486 .as_ref()
1487 .and_then(OmenaQueryClosedWorldOutcomeV0::bundle)
1488 {
1489 execute_omena_query_consumer_build_style_source_with_context_and_closed_world_bundle(
1490 target_style_path,
1491 target_source,
1492 &pass_set,
1493 &context,
1494 closed_world_bundle,
1495 closed_world_bundle_reachability_precision(&context, closed_world_bundle),
1496 options,
1497 )
1498 } else {
1499 execute_omena_query_consumer_build_style_source_with_open_world_context(
1500 target_style_path,
1501 target_source,
1502 &pass_set,
1503 &context,
1504 options,
1505 )
1506 };
1507 summary
1508 .ready_surfaces
1509 .push("multiSourceTransformContextProducer");
1510 Ok(summary)
1511}
1512
1513pub fn execute_omena_query_consumer_build_style_sources(
1514 target_style_path: &str,
1515 style_sources: &[OmenaQueryStyleSourceInputV0],
1516 requested_pass_ids: &[String],
1517 package_manifests: &[OmenaQueryStylePackageManifestV0],
1518) -> Result<OmenaQueryConsumerBuildSummaryV0, String> {
1519 execute_omena_query_consumer_build_style_sources_with_context(
1520 target_style_path,
1521 style_sources,
1522 requested_pass_ids,
1523 &TransformExecutionContextV0::default(),
1524 package_manifests,
1525 )
1526}
1527
1528pub fn execute_omena_query_consumer_build_style_source_for_target_query(
1529 style_path: &str,
1530 style_source: &str,
1531 target_query: &str,
1532) -> OmenaQueryConsumerBuildSummaryV0 {
1533 execute_omena_query_consumer_build_style_source_for_target_query_with_options(
1534 style_path,
1535 style_source,
1536 target_query,
1537 conservative_omena_query_target_options(),
1538 )
1539}
1540
1541pub fn execute_omena_query_consumer_build_style_source_for_target_query_with_options(
1542 style_path: &str,
1543 style_source: &str,
1544 target_query: &str,
1545 target_options: OmenaQueryTargetTransformOptionsV0,
1546) -> OmenaQueryConsumerBuildSummaryV0 {
1547 execute_omena_query_consumer_build_style_source_for_target_query_with_context_and_options(
1548 style_path,
1549 style_source,
1550 target_query,
1551 &TransformExecutionContextV0::default(),
1552 target_options,
1553 )
1554}
1555
1556pub fn execute_omena_query_consumer_build_style_source_for_target_query_with_context_and_options(
1557 style_path: &str,
1558 style_source: &str,
1559 target_query: &str,
1560 context: &TransformExecutionContextV0,
1561 target_options: OmenaQueryTargetTransformOptionsV0,
1562) -> OmenaQueryConsumerBuildSummaryV0 {
1563 execute_omena_query_consumer_build_style_source_for_target_query_with_context_options_and_additional_passes(
1564 style_path,
1565 style_source,
1566 target_query,
1567 context,
1568 target_options,
1569 &[],
1570 )
1571}
1572
1573pub fn execute_omena_query_consumer_build_style_source_for_target_query_with_context_options_and_additional_passes(
1574 style_path: &str,
1575 style_source: &str,
1576 target_query: &str,
1577 context: &TransformExecutionContextV0,
1578 target_options: OmenaQueryTargetTransformOptionsV0,
1579 additional_pass_ids: &[String],
1580) -> OmenaQueryConsumerBuildSummaryV0 {
1581 execute_omena_query_consumer_build_style_source_for_target_query_with_context_options_additional_passes_and_build_options(
1582 style_path,
1583 style_source,
1584 target_query,
1585 context,
1586 target_options,
1587 additional_pass_ids,
1588 &OmenaQueryConsumerBuildOptionsV0::default(),
1589 )
1590}
1591
1592pub fn execute_omena_query_consumer_build_style_source_for_target_query_with_context_options_additional_passes_and_build_options(
1593 style_path: &str,
1594 style_source: &str,
1595 target_query: &str,
1596 context: &TransformExecutionContextV0,
1597 target_options: OmenaQueryTargetTransformOptionsV0,
1598 additional_pass_ids: &[String],
1599 build_options: &OmenaQueryConsumerBuildOptionsV0,
1600) -> OmenaQueryConsumerBuildSummaryV0 {
1601 let context = merge_single_source_transform_context(style_path, style_source, context);
1602 let plan = summarize_omena_query_transform_plan_from_target_query_with_context(
1603 style_path,
1604 style_source,
1605 target_query,
1606 target_options,
1607 default_omena_query_transform_print_options(),
1608 &context,
1609 );
1610 let mut requested_pass_ids = plan
1611 .combined_pass_ids
1612 .iter()
1613 .map(|pass_id| (*pass_id).to_string())
1614 .collect::<Vec<_>>();
1615 extend_unique_pass_ids(&mut requested_pass_ids, additional_pass_ids);
1616 let mut execution_context = merge_target_options_transform_context(&context, target_options);
1617 execution_context.vendor_prefix_policy = plan
1618 .target_query
1619 .as_ref()
1620 .and_then(|target_query| target_query.vendor_prefix_policy);
1621 execution_context.supports_target_capability = plan
1622 .target_query
1623 .as_ref()
1624 .map(|target_query| supports_target_capability_from_feature_support(target_query.support));
1625 let execution_summary =
1626 execute_omena_query_consumer_build_style_source_with_context_and_options(
1627 style_path,
1628 style_source,
1629 &requested_pass_ids,
1630 &execution_context,
1631 build_options,
1632 );
1633 let ready_surfaces = extend_ready_surfaces(
1634 execution_summary.ready_surfaces.clone(),
1635 ["targetQueryBuildFacade"],
1636 );
1637 let ready_surfaces = consumer_build_ready_surfaces_with_open_world_snapshot(
1638 execution_summary.open_world_snapshot.as_ref(),
1639 ready_surfaces,
1640 );
1641
1642 OmenaQueryConsumerBuildSummaryV0 {
1643 schema_version: "0",
1644 product: "omena-query.consumer-build-style-source",
1645 style_path: plan.style_path,
1646 dialect: plan.dialect,
1647 requested_pass_ids,
1648 effective_pass_ids: execution_summary.effective_pass_ids,
1649 target_query: plan.target_query,
1650 unknown_pass_ids: execution_summary.unknown_pass_ids,
1651 semantic_removal_count: execution_summary.semantic_removal_count,
1652 execution: execution_summary.execution,
1653 bundle: None,
1654 bundle_emission_path: None,
1655 source_map_v3: None,
1656 open_world_snapshot: execution_summary.open_world_snapshot,
1657 ready_surfaces,
1658 }
1659}
1660
1661pub fn execute_omena_query_consumer_build_style_sources_for_target_query_with_context_and_options(
1662 target_style_path: &str,
1663 style_sources: &[OmenaQueryStyleSourceInputV0],
1664 target_query: &str,
1665 context: &TransformExecutionContextV0,
1666 target_options: OmenaQueryTargetTransformOptionsV0,
1667 package_manifests: &[OmenaQueryStylePackageManifestV0],
1668) -> Result<OmenaQueryConsumerBuildSummaryV0, String> {
1669 let resolution_inputs = resolution_inputs_for_transform_style_sources(
1670 target_style_path,
1671 style_sources,
1672 package_manifests,
1673 );
1674 execute_omena_query_consumer_build_style_sources_for_target_query_with_context_and_options_and_resolution_inputs(
1675 target_style_path,
1676 style_sources,
1677 target_query,
1678 context,
1679 target_options,
1680 &resolution_inputs,
1681 )
1682}
1683
1684pub fn execute_omena_query_consumer_build_style_sources_for_target_query_with_context_and_options_and_resolution_inputs(
1685 target_style_path: &str,
1686 style_sources: &[OmenaQueryStyleSourceInputV0],
1687 target_query: &str,
1688 context: &TransformExecutionContextV0,
1689 target_options: OmenaQueryTargetTransformOptionsV0,
1690 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
1691) -> Result<OmenaQueryConsumerBuildSummaryV0, String> {
1692 execute_omena_query_consumer_build_style_sources_for_target_query_with_context_options_additional_passes_and_resolution_inputs(
1693 target_style_path,
1694 style_sources,
1695 target_query,
1696 context,
1697 target_options,
1698 &[],
1699 resolution_inputs,
1700 )
1701}
1702
1703pub fn execute_omena_query_consumer_build_style_sources_for_target_query_with_context_options_additional_passes_and_resolution_inputs(
1704 target_style_path: &str,
1705 style_sources: &[OmenaQueryStyleSourceInputV0],
1706 target_query: &str,
1707 context: &TransformExecutionContextV0,
1708 target_options: OmenaQueryTargetTransformOptionsV0,
1709 additional_pass_ids: &[String],
1710 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
1711) -> Result<OmenaQueryConsumerBuildSummaryV0, String> {
1712 let build_options = OmenaQueryConsumerBuildOptionsV0::default();
1713 execute_omena_query_consumer_build_style_sources_for_target_query_with_context_and_build_inputs(
1714 target_style_path,
1715 style_sources,
1716 target_query,
1717 context,
1718 OmenaQueryTargetConsumerBuildInputsV0 {
1719 target_options,
1720 additional_pass_ids,
1721 resolution_inputs,
1722 build_options: &build_options,
1723 },
1724 )
1725}
1726
1727#[derive(Debug, Clone, Copy)]
1728pub struct OmenaQueryTargetConsumerBuildInputsV0<'a> {
1729 pub target_options: OmenaQueryTargetTransformOptionsV0,
1730 pub additional_pass_ids: &'a [String],
1731 pub resolution_inputs: &'a OmenaQueryStyleResolutionInputsV0,
1732 pub build_options: &'a OmenaQueryConsumerBuildOptionsV0,
1733}
1734
1735pub fn execute_omena_query_consumer_build_style_sources_for_target_query_with_context_and_build_inputs(
1736 target_style_path: &str,
1737 style_sources: &[OmenaQueryStyleSourceInputV0],
1738 target_query: &str,
1739 context: &TransformExecutionContextV0,
1740 inputs: OmenaQueryTargetConsumerBuildInputsV0<'_>,
1741) -> Result<OmenaQueryConsumerBuildSummaryV0, String> {
1742 let OmenaQueryTargetConsumerBuildInputsV0 {
1743 target_options,
1744 additional_pass_ids,
1745 resolution_inputs,
1746 build_options,
1747 } = inputs;
1748 let Some(target_source) = find_target_style_source(target_style_path, style_sources) else {
1749 return Err(format!(
1750 "target style path {target_style_path:?} was not found in workspace style sources"
1751 ));
1752 };
1753 let context = merge_workspace_transform_context(
1754 target_style_path,
1755 style_sources,
1756 context,
1757 TransformResolutionContext::from_resolution_inputs(resolution_inputs),
1758 );
1759 let plan = summarize_omena_query_transform_plan_from_target_query_with_context(
1760 target_style_path,
1761 target_source,
1762 target_query,
1763 target_options,
1764 default_omena_query_transform_print_options(),
1765 &context,
1766 );
1767 let mut requested_pass_ids = plan
1768 .combined_pass_ids
1769 .iter()
1770 .map(|pass_id| (*pass_id).to_string())
1771 .collect::<Vec<_>>();
1772 extend_unique_pass_ids(&mut requested_pass_ids, additional_pass_ids);
1773 let mut execution_context = merge_target_options_transform_context(&context, target_options);
1774 execution_context.vendor_prefix_policy = plan
1775 .target_query
1776 .as_ref()
1777 .and_then(|target_query| target_query.vendor_prefix_policy);
1778 execution_context.supports_target_capability = plan
1779 .target_query
1780 .as_ref()
1781 .map(|target_query| supports_target_capability_from_feature_support(target_query.support));
1782 let execution_summary = execute_omena_query_consumer_build_style_sources_with_context_resolution_inputs_and_options(
1783 target_style_path,
1784 style_sources,
1785 &requested_pass_ids,
1786 &execution_context,
1787 resolution_inputs,
1788 build_options,
1789 )?;
1790 let ready_surfaces = extend_ready_surfaces(
1791 execution_summary.ready_surfaces.clone(),
1792 [
1793 "targetQueryBuildFacade",
1794 "multiSourceTransformContextProducer",
1795 ],
1796 );
1797 let ready_surfaces = consumer_build_ready_surfaces_with_open_world_snapshot(
1798 execution_summary.open_world_snapshot.as_ref(),
1799 ready_surfaces,
1800 );
1801
1802 Ok(OmenaQueryConsumerBuildSummaryV0 {
1803 schema_version: "0",
1804 product: "omena-query.consumer-build-style-source",
1805 style_path: plan.style_path,
1806 dialect: plan.dialect,
1807 requested_pass_ids,
1808 effective_pass_ids: execution_summary.effective_pass_ids,
1809 target_query: plan.target_query,
1810 unknown_pass_ids: execution_summary.unknown_pass_ids,
1811 semantic_removal_count: execution_summary.semantic_removal_count,
1812 execution: execution_summary.execution,
1813 bundle: None,
1814 bundle_emission_path: None,
1815 source_map_v3: None,
1816 open_world_snapshot: execution_summary.open_world_snapshot,
1817 ready_surfaces,
1818 })
1819}
1820
1821fn extend_unique_pass_ids(target: &mut Vec<String>, additional: &[String]) {
1822 for pass_id in additional {
1823 if !target.contains(pass_id) {
1824 target.push(pass_id.clone());
1825 }
1826 }
1827}
1828
1829fn supports_target_capability_from_feature_support(
1830 support: OmenaQueryTargetFeatureSupportV0,
1831) -> SupportsTargetCapabilityV0 {
1832 SupportsTargetCapabilityV0 {
1833 supports_light_dark: support.supports_light_dark,
1834 supports_color_mix: support.supports_color_mix,
1835 supports_oklch_oklab: support.supports_oklch_oklab,
1836 supports_color_function: support.supports_color_function,
1837 supports_relative_color: support.supports_relative_color,
1838 supports_logical_properties: support.supports_logical_properties,
1839 supports_css_nesting: support.supports_css_nesting,
1840 supports_css_scope: support.supports_css_scope,
1841 supports_cascade_layers: support.supports_cascade_layers,
1842 }
1843}
1844
1845pub fn execute_omena_query_consumer_build_style_sources_for_target_query_with_options(
1846 target_style_path: &str,
1847 style_sources: &[OmenaQueryStyleSourceInputV0],
1848 target_query: &str,
1849 target_options: OmenaQueryTargetTransformOptionsV0,
1850 package_manifests: &[OmenaQueryStylePackageManifestV0],
1851) -> Result<OmenaQueryConsumerBuildSummaryV0, String> {
1852 execute_omena_query_consumer_build_style_sources_for_target_query_with_context_and_options(
1853 target_style_path,
1854 style_sources,
1855 target_query,
1856 &TransformExecutionContextV0::default(),
1857 target_options,
1858 package_manifests,
1859 )
1860}
1861
1862pub fn attach_omena_query_consumer_build_bundle_summary(
1863 summary: &mut OmenaQueryConsumerBuildSummaryV0,
1864 style_source: &str,
1865) {
1866 let bundle = summarize_omena_transform_bundle_from_source(
1867 &summary.style_path,
1868 style_source,
1869 omena_parser_dialect_for_style_path(&summary.style_path),
1870 );
1871 summary.bundle = Some(bundle);
1872 if !summary.ready_surfaces.contains(&"bundleAssetUrlResolution") {
1873 summary.ready_surfaces.push("bundleAssetUrlResolution");
1874 }
1875 if summary
1876 .bundle
1877 .as_ref()
1878 .is_some_and(|bundle| bundle.code_splitting_required)
1879 && !summary.ready_surfaces.contains(&"bundleCodeSplitPlan")
1880 {
1881 summary.ready_surfaces.push("bundleCodeSplitPlan");
1882 }
1883}
1884
1885pub fn summarize_omena_query_bundle_code_split_workspace_plan(
1886 primary_entry_style_path: &str,
1887 bundle_entry_style_paths: &[String],
1888 style_sources: &[OmenaQueryStyleSourceInputV0],
1889 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
1890) -> Result<OmenaQueryBundleCodeSplitWorkspacePlanV0, String> {
1891 let available_style_paths = style_sources
1892 .iter()
1893 .map(|source| source.style_path.as_str())
1894 .collect::<BTreeSet<_>>();
1895 let dependency_specifiers_by_path =
1896 collect_omena_query_bundle_code_split_dependency_specifiers(style_sources);
1897 let mut entry_style_paths = vec![primary_entry_style_path.to_string()];
1898 for configured_entry in bundle_entry_style_paths {
1899 if configured_entry != primary_entry_style_path
1900 && !entry_style_paths.contains(configured_entry)
1901 {
1902 entry_style_paths.push(configured_entry.clone());
1903 }
1904 }
1905 for entry_style_path in &entry_style_paths {
1906 if !available_style_paths.contains(entry_style_path.as_str()) {
1907 return Err(format!(
1908 "bundle entry source is not loaded: {entry_style_path}"
1909 ));
1910 }
1911 }
1912
1913 let entry_style_path_set = entry_style_paths.iter().cloned().collect::<BTreeSet<_>>();
1914 let entry_reachability = collect_omena_query_bundle_code_split_entry_reachability(
1915 entry_style_paths.as_slice(),
1916 &dependency_specifiers_by_path,
1917 &available_style_paths,
1918 resolution_inputs,
1919 );
1920
1921 let mut outputs = Vec::new();
1922 for (style_path, reachable_from_entries) in entry_reachability {
1923 let split_boundary = omena_query_bundle_code_split_boundary(
1924 style_path.as_str(),
1925 primary_entry_style_path,
1926 &entry_style_path_set,
1927 reachable_from_entries.len(),
1928 );
1929 outputs.push(OmenaQueryBundleCodeSplitWorkspacePlanOutputV0 {
1930 is_entry: entry_style_path_set.contains(style_path.as_str()),
1931 source_path: style_path,
1932 split_boundary,
1933 reachable_from_entries: reachable_from_entries.into_iter().collect(),
1934 });
1935 }
1936 let configured_entry_count = outputs
1937 .iter()
1938 .filter(|output| output.split_boundary == "entryConfig")
1939 .count();
1940 let shared_boundary_count = outputs
1941 .iter()
1942 .filter(|output| output.split_boundary == "shared")
1943 .count();
1944 let mut ready_surfaces = vec!["bundleCodeSplitPlan", "bundleCodeSplitBoundaryPlan"];
1945 if configured_entry_count > 0 {
1946 ready_surfaces.push("bundleCodeSplitEntryConfig");
1947 }
1948 if shared_boundary_count > 0 {
1949 ready_surfaces.push("bundleCodeSplitSharedChunkPlan");
1950 }
1951
1952 Ok(OmenaQueryBundleCodeSplitWorkspacePlanV0 {
1953 schema_version: "0",
1954 product: "omena-query.bundle-code-split-workspace-plan",
1955 primary_entry_style_path: primary_entry_style_path.to_string(),
1956 configured_entry_count,
1957 output_count: outputs.len(),
1958 shared_boundary_count,
1959 outputs,
1960 ready_surfaces,
1961 })
1962}
1963
1964fn collect_omena_query_bundle_code_split_dependency_specifiers(
1965 style_sources: &[OmenaQueryStyleSourceInputV0],
1966) -> BTreeMap<&str, Vec<String>> {
1967 let modules = style_sources_to_transform_bundle_modules(style_sources);
1968 let projection =
1969 project_omena_transform_bundle_linker_inputs_from_parsed_modules(&modules, &[]);
1970 let projection_path_by_source_path =
1971 projection_path_by_source_path(modules.as_slice(), style_sources);
1972 let dependency_specifiers_by_projection_path = projection
1973 .inputs()
1974 .iter()
1975 .map(|input| {
1976 let specifiers = input
1977 .dependency_edges
1978 .iter()
1979 .filter(|edge| bundle_edge_is_module_dependency(edge.kind))
1980 .map(|edge| edge.import_source.clone())
1981 .collect::<Vec<_>>();
1982 (input.source_path.as_str(), specifiers)
1983 })
1984 .collect::<BTreeMap<_, _>>();
1985
1986 style_sources
1987 .iter()
1988 .map(|source| {
1989 let specifiers = projection_path_by_source_path
1990 .get(source.style_path.as_str())
1991 .and_then(|projection_path| {
1992 dependency_specifiers_by_projection_path.get(projection_path.as_str())
1993 })
1994 .cloned()
1995 .unwrap_or_default();
1996 (source.style_path.as_str(), specifiers)
1997 })
1998 .collect()
1999}
2000
2001fn collect_omena_query_bundle_code_split_entry_reachability(
2002 entry_style_paths: &[String],
2003 dependency_specifiers_by_path: &BTreeMap<&str, Vec<String>>,
2004 available_style_paths: &BTreeSet<&str>,
2005 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
2006) -> BTreeMap<String, BTreeSet<String>> {
2007 let resolution_context = TransformResolutionContext::from_resolution_inputs(resolution_inputs);
2008 let mut reachability = BTreeMap::<String, BTreeSet<String>>::new();
2009
2010 for entry_style_path in entry_style_paths {
2011 let mut visited = BTreeSet::new();
2012 let mut stack = vec![entry_style_path.clone()];
2013
2014 while let Some(style_path) = stack.pop() {
2015 if !visited.insert(style_path.clone()) {
2016 continue;
2017 }
2018 let Some(import_sources) = dependency_specifiers_by_path.get(style_path.as_str())
2019 else {
2020 continue;
2021 };
2022 reachability
2023 .entry(style_path.clone())
2024 .or_default()
2025 .insert(entry_style_path.clone());
2026 for import_source in import_sources {
2027 let Some(target_path) = resolution_context.resolve_style_module_source(
2028 style_path.as_str(),
2029 import_source,
2030 available_style_paths,
2031 ) else {
2032 continue;
2033 };
2034 if dependency_specifiers_by_path.contains_key(target_path.as_str()) {
2035 stack.push(target_path);
2036 }
2037 }
2038 }
2039 }
2040
2041 reachability
2042}
2043
2044fn omena_query_bundle_code_split_boundary(
2045 style_path: &str,
2046 primary_entry_style_path: &str,
2047 entry_style_paths: &BTreeSet<String>,
2048 reachable_entry_count: usize,
2049) -> &'static str {
2050 if style_path == primary_entry_style_path {
2051 return "entry";
2052 }
2053 if entry_style_paths.contains(style_path) {
2054 return "entryConfig";
2055 }
2056 if reachable_entry_count > 1 {
2057 return "shared";
2058 }
2059 "styleDependency"
2060}
2061
2062pub fn attach_omena_query_consumer_build_source_map_v3(
2063 summary: &mut OmenaQueryConsumerBuildSummaryV0,
2064 style_source: &str,
2065) {
2066 let style_source = OmenaQueryStyleSourceInputV0 {
2067 style_path: summary.style_path.clone(),
2068 style_source: style_source.to_string(),
2069 };
2070 attach_omena_query_consumer_build_source_map_v3_with_sources(summary, &[style_source], &[]);
2071}
2072
2073pub fn attach_omena_query_consumer_build_source_map_v3_with_sources(
2074 summary: &mut OmenaQueryConsumerBuildSummaryV0,
2075 style_sources: &[OmenaQueryStyleSourceInputV0],
2076 package_manifests: &[OmenaQueryStylePackageManifestV0],
2077) {
2078 let resolution_inputs = resolution_inputs_for_transform_style_sources(
2079 summary.style_path.as_str(),
2080 style_sources,
2081 package_manifests,
2082 );
2083 attach_omena_query_consumer_build_source_map_v3_with_sources_and_resolution_inputs(
2084 summary,
2085 style_sources,
2086 &resolution_inputs,
2087 );
2088}
2089
2090pub fn attach_omena_query_consumer_build_source_map_v3_with_sources_and_resolution_inputs(
2091 summary: &mut OmenaQueryConsumerBuildSummaryV0,
2092 style_sources: &[OmenaQueryStyleSourceInputV0],
2093 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
2094) {
2095 let source_map = summarize_omena_query_consumer_build_source_map_v3_with_resolution_inputs(
2096 &summary.style_path,
2097 style_sources,
2098 &summary.execution,
2099 resolution_inputs,
2100 );
2101 summary.source_map_v3 = Some(source_map);
2102 if !summary.ready_surfaces.contains(&"sourceMapV3Serializer") {
2103 summary.ready_surfaces.push("sourceMapV3Serializer");
2104 }
2105 if summary
2106 .source_map_v3
2107 .as_ref()
2108 .is_some_and(|source_map| source_map.sources.len() > 1)
2109 && !summary
2110 .ready_surfaces
2111 .contains(&"bundleSourceMapOriginChain")
2112 {
2113 summary.ready_surfaces.push("bundleSourceMapOriginChain");
2114 }
2115}
2116
2117pub fn summarize_omena_query_consumer_build_source_map_v3(
2118 style_path: &str,
2119 style_sources: &[OmenaQueryStyleSourceInputV0],
2120 execution: &TransformExecutionSummaryV0,
2121 package_manifests: &[OmenaQueryStylePackageManifestV0],
2122) -> OmenaQueryTransformSourceMapV3V0 {
2123 let resolution_inputs =
2124 resolution_inputs_for_transform_style_sources(style_path, style_sources, package_manifests);
2125 summarize_omena_query_consumer_build_source_map_v3_with_resolution_inputs(
2126 style_path,
2127 style_sources,
2128 execution,
2129 &resolution_inputs,
2130 )
2131}
2132
2133pub fn summarize_omena_query_consumer_build_source_map_v3_with_resolution_inputs(
2134 style_path: &str,
2135 style_sources: &[OmenaQueryStyleSourceInputV0],
2136 execution: &TransformExecutionSummaryV0,
2137 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
2138) -> OmenaQueryTransformSourceMapV3V0 {
2139 let source_by_path = style_sources
2140 .iter()
2141 .map(|source| (source.style_path.as_str(), source.style_source.as_str()))
2142 .collect::<BTreeMap<_, _>>();
2143 let style_source = source_by_path.get(style_path).copied().unwrap_or_default();
2144 let dialect = omena_parser_dialect_for_style_path(style_path);
2145 let artifact = print_transform_execution_artifact_with_dialect_and_source(
2146 style_path,
2147 style_source,
2148 dialect,
2149 format!(
2150 "omena-query-consumer-build-source-map-v3:{}:{}",
2151 style_path,
2152 style_source.len()
2153 ),
2154 &[TransformPassKind::PrintCss],
2155 default_omena_query_transform_print_options(),
2156 execution,
2157 );
2158 let available_style_paths = source_by_path.keys().copied().collect::<BTreeSet<_>>();
2159 let mut segments = artifact.source_map_segments.clone();
2160 segments.extend(import_inline_source_map_segments(
2161 style_path,
2162 execution,
2163 &source_by_path,
2164 &available_style_paths,
2165 TransformResolutionContext::from_resolution_inputs(resolution_inputs),
2166 ));
2167 let source_contents = style_sources
2168 .iter()
2169 .map(|source| (source.style_path.as_str(), source.style_source.as_str()))
2170 .collect::<Vec<_>>();
2171 serialize_transform_source_map_v3_with_source_contents(
2172 style_path,
2173 execution.output_css.as_str(),
2174 style_path,
2175 source_contents.as_slice(),
2176 segments.as_slice(),
2177 )
2178}
2179
2180fn summarize_omena_query_linked_bundle_source_map_v3(
2181 style_path: &str,
2182 style_sources: &[OmenaQueryStyleSourceInputV0],
2183 execution: &TransformExecutionSummaryV0,
2184 materialization: &LinkedEmissionArtifactV0,
2185 module_executions: &[LinkedModuleExecutionV0],
2186) -> Result<
2187 (
2188 OmenaQueryTransformSourceMapV3V0,
2189 Vec<OmenaQueryLinkedSourceMapDispositionV0>,
2190 ),
2191 String,
2192> {
2193 let (segments, dispositions) = linked_bundle_source_map_segments(
2194 style_sources,
2195 execution.output_css.as_str(),
2196 materialization,
2197 module_executions,
2198 )?;
2199 let source_contents = style_sources
2200 .iter()
2201 .map(|source| (source.style_path.as_str(), source.style_source.as_str()))
2202 .collect::<Vec<_>>();
2203 let mut source_map = serialize_transform_source_map_v3_with_source_contents(
2204 style_path,
2205 execution.output_css.as_str(),
2206 style_path,
2207 source_contents.as_slice(),
2208 segments.as_slice(),
2209 );
2210 source_map.x_omena_pass_ids = linked_bundle_source_map_pass_ids(
2211 module_executions,
2212 source_map.x_omena_pass_ids.as_slice(),
2213 );
2214 Ok((source_map, dispositions))
2215}
2216
2217fn linked_bundle_source_map_pass_ids(
2218 module_executions: &[LinkedModuleExecutionV0],
2219 emission_pass_ids: &[&'static str],
2220) -> Vec<&'static str> {
2221 module_executions
2222 .iter()
2223 .flat_map(|module| module.execution.executed_pass_ids.iter().copied())
2224 .chain(emission_pass_ids.iter().copied())
2225 .collect::<BTreeSet<_>>()
2226 .into_iter()
2227 .collect()
2228}
2229
2230fn linked_bundle_source_map_segments(
2231 style_sources: &[OmenaQueryStyleSourceInputV0],
2232 generated_css: &str,
2233 materialization: &LinkedEmissionArtifactV0,
2234 module_executions: &[LinkedModuleExecutionV0],
2235) -> Result<
2236 (
2237 Vec<TransformSourceMapSegmentV0>,
2238 Vec<OmenaQueryLinkedSourceMapDispositionV0>,
2239 ),
2240 String,
2241> {
2242 let source_by_path = style_sources
2243 .iter()
2244 .map(|source| (source.style_path.as_str(), source.style_source.as_str()))
2245 .collect::<BTreeMap<_, _>>();
2246 let execution_by_instance = module_executions
2247 .iter()
2248 .map(|module| (&module.module_instance, &module.execution))
2249 .collect::<BTreeMap<_, _>>();
2250 let mut segments = Vec::new();
2251 let mut dispositions = Vec::new();
2252 for region in &materialization.module_regions {
2253 let source_path = region.module_instance.module().as_str();
2254 let source = source_by_path.get(source_path).copied().ok_or_else(|| {
2255 format!("linked source-map module {source_path:?} has no source document")
2256 })?;
2257 let module_execution = execution_by_instance
2258 .get(®ion.module_instance)
2259 .copied()
2260 .ok_or_else(|| {
2261 format!(
2262 "linked source-map module {:?} has no retained execution",
2263 region.module_instance
2264 )
2265 })?;
2266 if region.generated_start > region.generated_end
2267 || region.generated_end > generated_css.len()
2268 {
2269 return Err(format!(
2270 "linked source-map region for {source_path:?} is outside generated CSS: {}..{} of {}",
2271 region.generated_start,
2272 region.generated_end,
2273 generated_css.len()
2274 ));
2275 }
2276 let (mut module_segments, granularity, fallback_reason) =
2277 if source == module_execution.output_css {
2278 let artifact = print_omena_query_transform_source_with_pretty_options(
2279 source_path,
2280 source,
2281 transform_print_dialect_for_style_path(source_path),
2282 format!("linked-module-source-map:{source_path}"),
2283 &[],
2284 default_omena_query_transform_print_options(),
2285 OmenaQueryPrettyFormatOptionsV0 {
2286 line_width: 100,
2287 indent_width: 2,
2288 },
2289 );
2290 (
2291 artifact.source_map_segments,
2292 OmenaQueryLinkedSourceMapGranularityV0::CstAnchors,
2293 None,
2294 )
2295 } else {
2296 let (segment, fallback_reason) = linked_whole_module_fallback_segment(
2297 source_path,
2298 source,
2299 module_execution.output_css.as_str(),
2300 );
2301 (
2302 vec![segment],
2303 OmenaQueryLinkedSourceMapGranularityV0::WholeModuleFallback,
2304 Some(fallback_reason),
2305 )
2306 };
2307 for segment in &module_segments {
2308 validate_linked_source_map_original_segment(
2309 source_path,
2310 source,
2311 module_execution.output_css.as_str(),
2312 segment,
2313 granularity,
2314 fallback_reason,
2315 )?;
2316 }
2317 let segment_start = segments.len();
2318 for segment in &mut module_segments {
2319 segment.generated_start += region.generated_start;
2320 segment.generated_end += region.generated_start;
2321 if segment.generated_start < region.generated_start
2322 || segment.generated_end > region.generated_end
2323 {
2324 return Err(format!(
2325 "linked source-map segment for {source_path:?} is outside its materialized region: {}..{} not within {}..{}",
2326 segment.generated_start,
2327 segment.generated_end,
2328 region.generated_start,
2329 region.generated_end
2330 ));
2331 }
2332 segment.generated_start_point =
2333 transform_source_map_point(generated_css, segment.generated_start);
2334 segment.generated_end_point =
2335 transform_source_map_point(generated_css, segment.generated_end);
2336 segment.pass_id = "linked-order-emission";
2337 }
2338 segments.extend(module_segments);
2339 dispositions.push(OmenaQueryLinkedSourceMapDispositionV0 {
2340 module_instance: region.module_instance.clone(),
2341 granularity,
2342 fallback_reason,
2343 segment_count: segments.len() - segment_start,
2344 });
2345 }
2346 Ok((segments, dispositions))
2347}
2348
2349pub(crate) const LINKED_FALLBACK_EXACT_TOKEN_REASON: &str =
2350 "module output differs; fallback anchors a unique surviving token sequence";
2351pub(crate) const LINKED_FALLBACK_AMBIGUOUS_TOKEN_REASON: &str = "module output differs; fallback uses source-start convention because the surviving token sequence is ambiguous";
2352pub(crate) const LINKED_FALLBACK_SOURCE_START_REASON: &str =
2353 "module output differs; fallback uses source-start convention without token correspondence";
2354
2355#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2356enum LinkedFallbackSourceTokenRangeV0 {
2357 NoMatch,
2358 Unique { start: usize, end: usize },
2359 Ambiguous,
2360}
2361
2362fn linked_whole_module_fallback_segment(
2363 source_path: &str,
2364 source: &str,
2365 generated_module_css: &str,
2366) -> (TransformSourceMapSegmentV0, &'static str) {
2367 let token_range =
2368 linked_fallback_exact_source_token_range(source_path, source, generated_module_css);
2369 let (original_start, original_end, reason) = match token_range {
2370 LinkedFallbackSourceTokenRangeV0::Unique { start, end } => {
2371 (start, end, LINKED_FALLBACK_EXACT_TOKEN_REASON)
2372 }
2373 LinkedFallbackSourceTokenRangeV0::Ambiguous => (
2374 linked_fallback_source_start(source_path, source),
2375 source.len(),
2376 LINKED_FALLBACK_AMBIGUOUS_TOKEN_REASON,
2377 ),
2378 LinkedFallbackSourceTokenRangeV0::NoMatch => (
2379 linked_fallback_source_start(source_path, source),
2380 source.len(),
2381 LINKED_FALLBACK_SOURCE_START_REASON,
2382 ),
2383 };
2384 (
2385 TransformSourceMapSegmentV0 {
2386 source_path: source_path.to_string(),
2387 original_start,
2388 original_end,
2389 generated_start: 0,
2390 generated_end: generated_module_css.len(),
2391 original_start_point: transform_source_map_point(source, original_start),
2392 original_end_point: transform_source_map_point(source, original_end),
2393 generated_start_point: transform_source_map_point(generated_module_css, 0),
2394 generated_end_point: transform_source_map_point(
2395 generated_module_css,
2396 generated_module_css.len(),
2397 ),
2398 pass_id: "linked-order-emission",
2399 },
2400 reason,
2401 )
2402}
2403
2404fn linked_fallback_exact_source_token_range(
2405 source_path: &str,
2406 source: &str,
2407 generated_module_css: &str,
2408) -> LinkedFallbackSourceTokenRangeV0 {
2409 let dialect = omena_parser_dialect_for_style_path(source_path);
2410 let source_lexed = lex_omena_query_omena_parser_style_source(source, dialect);
2411 let generated_lexed = lex_omena_query_omena_parser_style_source(generated_module_css, dialect);
2412 if !source_lexed.errors().is_empty() || !generated_lexed.errors().is_empty() {
2413 return LinkedFallbackSourceTokenRangeV0::NoMatch;
2414 }
2415 let source_tokens = canonical_linked_fallback_tokens(source_lexed.tokens());
2416 let generated_tokens = canonical_linked_fallback_tokens(generated_lexed.tokens());
2417 if generated_tokens.is_empty() || source_tokens.len() < generated_tokens.len() {
2418 return LinkedFallbackSourceTokenRangeV0::NoMatch;
2419 }
2420 let mut matching_ranges = source_tokens
2421 .windows(generated_tokens.len())
2422 .filter(|window| {
2423 window
2424 .iter()
2425 .zip(&generated_tokens)
2426 .all(|(source_token, generated_token)| {
2427 source_token.kind == generated_token.kind
2428 && source_token.text == generated_token.text
2429 })
2430 })
2431 .filter_map(|window| {
2432 let first = window.first()?;
2433 let last = window.last()?;
2434 Some((
2435 u32::from(first.range.start()) as usize,
2436 u32::from(last.range.end()) as usize,
2437 ))
2438 });
2439 let Some((start, end)) = matching_ranges.next() else {
2440 return LinkedFallbackSourceTokenRangeV0::NoMatch;
2441 };
2442 if matching_ranges.next().is_some() {
2443 LinkedFallbackSourceTokenRangeV0::Ambiguous
2444 } else {
2445 LinkedFallbackSourceTokenRangeV0::Unique { start, end }
2446 }
2447}
2448
2449fn linked_fallback_source_start(source_path: &str, source: &str) -> usize {
2450 let dialect = omena_parser_dialect_for_style_path(source_path);
2451 let lexed = lex_omena_query_omena_parser_style_source(source, dialect);
2452 if !lexed.errors().is_empty() {
2453 return source.len();
2454 }
2455 let tokens = lexed
2456 .tokens()
2457 .iter()
2458 .filter(|token| !token.kind.is_trivia())
2459 .collect::<Vec<_>>();
2460 let mut cursor = 0;
2461 while tokens.get(cursor).is_some_and(|token| {
2462 token.kind == omena_syntax::SyntaxKind::AtKeyword
2463 && token.text.eq_ignore_ascii_case("@import")
2464 }) {
2465 let Some(relative_end) = tokens[cursor..]
2466 .iter()
2467 .position(|token| token.kind == omena_syntax::SyntaxKind::Semicolon)
2468 else {
2469 return source.len();
2470 };
2471 cursor += relative_end + 1;
2472 }
2473 tokens.get(cursor).map_or(source.len(), |token| {
2474 u32::from(token.range.start()) as usize
2475 })
2476}
2477
2478fn canonical_linked_fallback_tokens(
2479 tokens: &[omena_parser::LexedToken],
2480) -> Vec<&omena_parser::LexedToken> {
2481 let non_trivia = tokens
2482 .iter()
2483 .filter(|token| !token.kind.is_trivia())
2484 .collect::<Vec<_>>();
2485 non_trivia
2486 .iter()
2487 .enumerate()
2488 .filter_map(|(index, token)| {
2489 let optional_terminal_semicolon = token.kind == omena_syntax::SyntaxKind::Semicolon
2490 && non_trivia
2491 .get(index + 1)
2492 .is_some_and(|next| next.kind == omena_syntax::SyntaxKind::RightBrace);
2493 (!optional_terminal_semicolon).then_some(*token)
2494 })
2495 .collect()
2496}
2497
2498fn validate_linked_source_map_original_segment(
2499 source_path: &str,
2500 source: &str,
2501 generated_module_css: &str,
2502 segment: &TransformSourceMapSegmentV0,
2503 granularity: OmenaQueryLinkedSourceMapGranularityV0,
2504 fallback_reason: Option<&str>,
2505) -> Result<(), String> {
2506 if segment.source_path != source_path
2507 || segment.original_start > segment.original_end
2508 || segment.original_end > source.len()
2509 || !source.is_char_boundary(segment.original_start)
2510 || !source.is_char_boundary(segment.original_end)
2511 {
2512 return Err(format!(
2513 "linked source-map segment for {source_path:?} has invalid original range {}..{} of {}",
2514 segment.original_start,
2515 segment.original_end,
2516 source.len()
2517 ));
2518 }
2519 let expected_start_point = transform_source_map_point(source, segment.original_start);
2520 let expected_end_point = transform_source_map_point(source, segment.original_end);
2521 if segment.original_start_point != expected_start_point
2522 || segment.original_end_point != expected_end_point
2523 {
2524 return Err(format!(
2525 "linked source-map segment for {source_path:?} has original points inconsistent with {}..{}",
2526 segment.original_start, segment.original_end
2527 ));
2528 }
2529 if granularity == OmenaQueryLinkedSourceMapGranularityV0::WholeModuleFallback {
2530 let token_range =
2531 linked_fallback_exact_source_token_range(source_path, source, generated_module_css);
2532 let expected_source_start = linked_fallback_source_start(source_path, source);
2533 match fallback_reason {
2534 Some(LINKED_FALLBACK_EXACT_TOKEN_REASON)
2535 if token_range
2536 != (LinkedFallbackSourceTokenRangeV0::Unique {
2537 start: segment.original_start,
2538 end: segment.original_end,
2539 }) =>
2540 {
2541 return Err(format!(
2542 "linked source-map fallback for {source_path:?} claims correspondence without one unique matching token window"
2543 ));
2544 }
2545 Some(LINKED_FALLBACK_AMBIGUOUS_TOKEN_REASON) => {
2546 if token_range != LinkedFallbackSourceTokenRangeV0::Ambiguous
2547 || segment.original_start != expected_source_start
2548 || segment.original_end != source.len()
2549 {
2550 return Err(format!(
2551 "linked source-map fallback for {source_path:?} has a dishonest ambiguous-token convention"
2552 ));
2553 }
2554 }
2555 Some(LINKED_FALLBACK_SOURCE_START_REASON) => {
2556 if token_range != LinkedFallbackSourceTokenRangeV0::NoMatch
2557 || segment.original_start != expected_source_start
2558 || segment.original_end != source.len()
2559 {
2560 return Err(format!(
2561 "linked source-map fallback for {source_path:?} has a dishonest source-start convention"
2562 ));
2563 }
2564 }
2565 Some(LINKED_FALLBACK_EXACT_TOKEN_REASON) => {}
2566 _ => {
2567 return Err(format!(
2568 "linked source-map fallback for {source_path:?} has no recognized anchor disclosure"
2569 ));
2570 }
2571 }
2572 }
2573 Ok(())
2574}
2575
2576fn transform_print_dialect_for_style_path(style_path: &str) -> OmenaQueryTransformStyleDialect {
2577 if style_path.ends_with(".sass") {
2578 OmenaQueryTransformStyleDialect::Sass
2579 } else if style_path.ends_with(".scss") {
2580 OmenaQueryTransformStyleDialect::Scss
2581 } else if style_path.ends_with(".less") {
2582 OmenaQueryTransformStyleDialect::Less
2583 } else {
2584 OmenaQueryTransformStyleDialect::Css
2585 }
2586}
2587
2588pub fn summarize_omena_query_bundle_code_split_source_map_v3(
2589 output_file_name: &str,
2590 generated_css: &str,
2591 source_path: &str,
2592 source_content: &str,
2593) -> OmenaQueryTransformSourceMapV3V0 {
2594 let segment = TransformSourceMapSegmentV0 {
2595 source_path: source_path.to_string(),
2596 original_start: 0,
2597 original_end: source_content.len(),
2598 generated_start: 0,
2599 generated_end: generated_css.len(),
2600 original_start_point: transform_source_map_point(source_content, 0),
2601 original_end_point: transform_source_map_point(source_content, source_content.len()),
2602 generated_start_point: transform_source_map_point(generated_css, 0),
2603 generated_end_point: transform_source_map_point(generated_css, generated_css.len()),
2604 pass_id: "code-split-emission",
2605 };
2606 serialize_transform_source_map_v3_with_source_contents(
2607 output_file_name,
2608 generated_css,
2609 source_path,
2610 &[(source_path, source_content)],
2611 &[segment],
2612 )
2613}
2614
2615fn import_inline_source_map_segments(
2616 style_path: &str,
2617 execution: &TransformExecutionSummaryV0,
2618 source_by_path: &BTreeMap<&str, &str>,
2619 available_style_paths: &BTreeSet<&str>,
2620 resolution_context: TransformResolutionContext<'_>,
2621) -> Vec<TransformSourceMapSegmentV0> {
2622 let mut segments = Vec::new();
2623 let mut seen_segments = BTreeSet::new();
2624 extend_import_graph_source_map_segments(
2625 &mut segments,
2626 &mut seen_segments,
2627 style_path,
2628 execution,
2629 source_by_path,
2630 available_style_paths,
2631 resolution_context,
2632 );
2633 let mut search_start = 0;
2634 for inline in &execution.css_import_inlines {
2635 if inline.replacement_css.is_empty() || search_start > execution.output_css.len() {
2636 continue;
2637 }
2638 let Some(resolved_style_path) = resolution_context.resolve_style_module_source(
2639 style_path,
2640 inline.import_source.as_str(),
2641 available_style_paths,
2642 ) else {
2643 continue;
2644 };
2645 let Some(imported_source) = source_by_path.get(resolved_style_path.as_str()).copied()
2646 else {
2647 continue;
2648 };
2649 let Some((generated_start, generated_end, _exact_match)) =
2650 find_import_origin_generated_range(
2651 execution.output_css.as_str(),
2652 search_start..execution.output_css.len(),
2653 &inline.replacement_css,
2654 resolved_style_path.as_str(),
2655 imported_source,
2656 )
2657 else {
2658 continue;
2659 };
2660 push_unique_import_origin_segment(
2661 &mut segments,
2662 &mut seen_segments,
2663 resolved_style_path,
2664 imported_source,
2665 execution.output_css.as_str(),
2666 generated_start,
2667 generated_end,
2668 );
2669 search_start = generated_end;
2670 }
2671 segments
2672}
2673
2674fn extend_import_graph_source_map_segments(
2675 segments: &mut Vec<TransformSourceMapSegmentV0>,
2676 seen_segments: &mut BTreeSet<(String, usize, usize, &'static str)>,
2677 style_path: &str,
2678 execution: &TransformExecutionSummaryV0,
2679 source_by_path: &BTreeMap<&str, &str>,
2680 available_style_paths: &BTreeSet<&str>,
2681 resolution_context: TransformResolutionContext<'_>,
2682) {
2683 let style_sources = source_by_path
2684 .iter()
2685 .map(|(style_path, style_source)| (*style_path, *style_source))
2686 .collect::<Vec<_>>();
2687 let style_fact_entries = collect_omena_query_style_fact_entries(style_sources.as_slice());
2688 let entries_by_path = style_fact_entries
2689 .iter()
2690 .map(|entry| (entry.style_path.as_str(), entry))
2691 .collect::<BTreeMap<_, _>>();
2692 let owned_source_by_path = source_by_path
2693 .iter()
2694 .map(|(style_path, style_source)| ((*style_path).to_string(), (*style_source).to_string()))
2695 .collect::<BTreeMap<_, _>>();
2696 let mut visiting = BTreeSet::new();
2697 let context = ImportGraphSourceMapSegmentContext {
2698 output_css: execution.output_css.as_str(),
2699 entries_by_path: &entries_by_path,
2700 owned_source_by_path: &owned_source_by_path,
2701 source_by_path,
2702 available_style_paths,
2703 resolution_context,
2704 };
2705 collect_import_graph_source_map_segments(
2706 segments,
2707 seen_segments,
2708 style_path,
2709 0,
2710 execution.output_css.len(),
2711 &context,
2712 &mut visiting,
2713 );
2714}
2715
2716struct ImportGraphSourceMapSegmentContext<'a> {
2717 output_css: &'a str,
2718 entries_by_path: &'a BTreeMap<&'a str, &'a OmenaQueryStyleFactEntry>,
2719 owned_source_by_path: &'a BTreeMap<String, String>,
2720 source_by_path: &'a BTreeMap<&'a str, &'a str>,
2721 available_style_paths: &'a BTreeSet<&'a str>,
2722 resolution_context: TransformResolutionContext<'a>,
2723}
2724
2725fn collect_import_graph_source_map_segments(
2726 segments: &mut Vec<TransformSourceMapSegmentV0>,
2727 seen_segments: &mut BTreeSet<(String, usize, usize, &'static str)>,
2728 importer_style_path: &str,
2729 generated_start_bound: usize,
2730 generated_end_bound: usize,
2731 context: &ImportGraphSourceMapSegmentContext<'_>,
2732 visiting: &mut BTreeSet<String>,
2733) {
2734 if !visiting.insert(importer_style_path.to_string()) {
2735 return;
2736 }
2737 let Some(entry) = context.entries_by_path.get(importer_style_path) else {
2738 visiting.remove(importer_style_path);
2739 return;
2740 };
2741
2742 for edge in entry
2743 .facts
2744 .sass_module_edges
2745 .iter()
2746 .filter(|edge| edge.kind == "sassImport")
2747 {
2748 let Some(resolved_style_path) = context.resolution_context.resolve_style_module_source(
2749 importer_style_path,
2750 edge.source.as_str(),
2751 context.available_style_paths,
2752 ) else {
2753 continue;
2754 };
2755 let Some(imported_source) = context
2756 .source_by_path
2757 .get(resolved_style_path.as_str())
2758 .copied()
2759 else {
2760 continue;
2761 };
2762 let Some(replacement_css) = resolve_import_inline_replacement_for_transform_context(
2763 resolved_style_path.as_str(),
2764 context.entries_by_path,
2765 context.available_style_paths,
2766 context.owned_source_by_path,
2767 context.resolution_context,
2768 &mut BTreeSet::new(),
2769 ) else {
2770 continue;
2771 };
2772 if replacement_css.is_empty() || generated_start_bound > generated_end_bound {
2773 continue;
2774 }
2775 let Some((generated_start, generated_end, exact_match)) =
2776 find_import_origin_generated_range(
2777 context.output_css,
2778 generated_start_bound..generated_end_bound,
2779 replacement_css.as_str(),
2780 resolved_style_path.as_str(),
2781 imported_source,
2782 )
2783 else {
2784 continue;
2785 };
2786 push_unique_import_origin_segment(
2787 segments,
2788 seen_segments,
2789 resolved_style_path.clone(),
2790 imported_source,
2791 context.output_css,
2792 generated_start,
2793 generated_end,
2794 );
2795 collect_import_graph_source_map_segments(
2796 segments,
2797 seen_segments,
2798 resolved_style_path.as_str(),
2799 if exact_match {
2800 generated_start
2801 } else {
2802 generated_start_bound
2803 },
2804 if exact_match {
2805 generated_end
2806 } else {
2807 generated_end_bound
2808 },
2809 context,
2810 visiting,
2811 );
2812 }
2813
2814 visiting.remove(importer_style_path);
2815}
2816
2817fn find_import_origin_generated_range(
2818 output_css: &str,
2819 search_range: std::ops::Range<usize>,
2820 replacement_css: &str,
2821 source_path: &str,
2822 source: &str,
2823) -> Option<(usize, usize, bool)> {
2824 if search_range.start > search_range.end || search_range.end > output_css.len() {
2825 return None;
2826 }
2827 if let Some(relative_start) = output_css[search_range.clone()].find(replacement_css) {
2828 let generated_start = search_range.start + relative_start;
2829 return Some((
2830 generated_start,
2831 generated_start + replacement_css.len(),
2832 true,
2833 ));
2834 }
2835
2836 let runtime_index =
2837 omena_semantic::summarize_style_runtime_index_facts_from_source(source_path, source);
2838 let mut candidate_needles = Vec::new();
2839 if let Some(runtime_index) = runtime_index {
2840 candidate_needles.extend(
2841 runtime_index
2842 .class_selector_names
2843 .iter()
2844 .map(|name| format!(".{name}")),
2845 );
2846 candidate_needles.extend(runtime_index.custom_property_names.iter().map(|name| {
2847 let mut rendered = String::new();
2848 let _ = omena_syntax::ident::render_authored(name, &mut rendered);
2849 rendered
2850 }));
2851 candidate_needles.extend(
2852 runtime_index
2853 .keyframe_names
2854 .iter()
2855 .map(|name| format!("@keyframes {name}")),
2856 );
2857 } else {
2858 let facts = summarize_omena_query_omena_parser_style_facts(
2859 source,
2860 omena_parser_dialect_for_style_path(source_path),
2861 );
2862 candidate_needles.extend(
2863 facts
2864 .class_selector_names
2865 .iter()
2866 .map(|name| format!(".{name}")),
2867 );
2868 candidate_needles.extend(facts.custom_property_names.iter().map(|name| {
2869 let mut rendered = String::new();
2870 let _ = omena_syntax::ident::render_authored(name, &mut rendered);
2871 rendered
2872 }));
2873 candidate_needles.extend(
2874 facts
2875 .keyframe_names
2876 .iter()
2877 .map(|name| format!("@keyframes {name}")),
2878 );
2879 }
2880
2881 let mut generated_start = None;
2882 let mut generated_end = None;
2883 for needle in candidate_needles {
2884 if needle.is_empty() {
2885 continue;
2886 }
2887 let Some(relative_start) = output_css[search_range.clone()].find(needle.as_str()) else {
2888 continue;
2889 };
2890 let start = search_range.start + relative_start;
2891 let end = start + needle.len();
2892 generated_start = Some(generated_start.map_or(start, |current: usize| current.min(start)));
2893 generated_end = Some(generated_end.map_or(end, |current: usize| current.max(end)));
2894 }
2895
2896 match (generated_start, generated_end) {
2897 (Some(start), Some(end)) if start < end => Some((start, end, false)),
2898 _ => None,
2899 }
2900}
2901
2902fn push_unique_import_origin_segment(
2903 segments: &mut Vec<TransformSourceMapSegmentV0>,
2904 seen_segments: &mut BTreeSet<(String, usize, usize, &'static str)>,
2905 source_path: String,
2906 source: &str,
2907 output_css: &str,
2908 generated_start: usize,
2909 generated_end: usize,
2910) {
2911 let pass_id = TransformPassKind::ImportInline.id();
2912 if !seen_segments.insert((source_path.clone(), generated_start, generated_end, pass_id)) {
2913 return;
2914 }
2915 segments.push(TransformSourceMapSegmentV0 {
2916 source_path,
2917 original_start: 0,
2918 original_end: source.len(),
2919 generated_start,
2920 generated_end,
2921 original_start_point: transform_source_map_point(source, 0),
2922 original_end_point: transform_source_map_point(source, source.len()),
2923 generated_start_point: transform_source_map_point(output_css, generated_start),
2924 generated_end_point: transform_source_map_point(output_css, generated_end),
2925 pass_id,
2926 });
2927}
2928
2929fn derive_single_source_transform_context(
2930 style_path: &str,
2931 style_source: &str,
2932) -> TransformExecutionContextV0 {
2933 summarize_omena_query_transform_context_from_sources(
2934 style_path,
2935 [(style_path, style_source)],
2936 &[],
2937 )
2938 .context
2939}
2940
2941fn resolution_inputs_for_transform_style_sources(
2942 target_style_path: &str,
2943 style_sources: &[OmenaQueryStyleSourceInputV0],
2944 package_manifests: &[OmenaQueryStylePackageManifestV0],
2945) -> OmenaQueryStyleResolutionInputsV0 {
2946 let workspace_uri = infer_transform_workspace_uri(target_style_path, style_sources);
2947 load_omena_query_workspace_style_resolution_inputs(workspace_uri.as_deref(), package_manifests)
2948}
2949
2950fn infer_transform_workspace_uri(
2951 target_style_path: &str,
2952 style_sources: &[OmenaQueryStyleSourceInputV0],
2953) -> Option<String> {
2954 let target_path = path_from_transform_style_path(target_style_path);
2955 let target_parent = target_path.as_deref().and_then(Path::parent);
2956 if let Some(root) = target_parent.and_then(discover_transform_workspace_root) {
2957 return Some(transform_path_to_file_uri(root));
2958 }
2959
2960 style_sources
2961 .iter()
2962 .filter_map(|source| path_from_transform_style_path(source.style_path.as_str()))
2963 .filter_map(|path| {
2964 path.parent()
2965 .and_then(discover_transform_workspace_root)
2966 .map(transform_path_to_file_uri)
2967 })
2968 .next()
2969}
2970
2971fn path_from_transform_style_path(style_path: &str) -> Option<PathBuf> {
2972 if let Some(path) = style_path.strip_prefix("file://") {
2973 return Some(PathBuf::from(path));
2974 }
2975 if style_path.starts_with('/') {
2976 return Some(PathBuf::from(style_path));
2977 }
2978 None
2979}
2980
2981fn discover_transform_workspace_root(path: &Path) -> Option<&Path> {
2982 path.ancestors().find(|candidate| {
2983 [
2984 "tsconfig.json",
2985 "tsconfig.base.json",
2986 "jsconfig.json",
2987 "package.json",
2988 "vite.config.ts",
2989 "vite.config.mts",
2990 "vite.config.cts",
2991 "vite.config.js",
2992 "vite.config.mjs",
2993 "vite.config.cjs",
2994 "webpack.config.ts",
2995 "webpack.config.mts",
2996 "webpack.config.cts",
2997 "webpack.config.js",
2998 "webpack.config.mjs",
2999 "webpack.config.cjs",
3000 "next.config.ts",
3001 "next.config.mts",
3002 "next.config.cts",
3003 "next.config.js",
3004 "next.config.mjs",
3005 "next.config.cjs",
3006 ]
3007 .iter()
3008 .any(|marker| candidate.join(marker).is_file())
3009 })
3010}
3011
3012fn transform_path_to_file_uri(path: &Path) -> String {
3013 format!("file://{}", path.to_string_lossy())
3014}
3015
3016fn merge_single_source_transform_context(
3017 style_path: &str,
3018 style_source: &str,
3019 context: &TransformExecutionContextV0,
3020) -> TransformExecutionContextV0 {
3021 merge_transform_context(
3022 derive_single_source_transform_context(style_path, style_source),
3023 context,
3024 )
3025}
3026
3027fn merge_workspace_transform_context(
3028 target_style_path: &str,
3029 style_sources: &[OmenaQueryStyleSourceInputV0],
3030 context: &TransformExecutionContextV0,
3031 resolution_context: TransformResolutionContext<'_>,
3032) -> TransformExecutionContextV0 {
3033 let style_refs = style_sources
3034 .iter()
3035 .map(|source| (source.style_path.as_str(), source.style_source.as_str()))
3036 .collect::<Vec<_>>();
3037 let derived = summarize_omena_query_transform_context_from_sources_with_resolution_context(
3038 target_style_path,
3039 style_refs,
3040 resolution_context,
3041 )
3042 .context;
3043 merge_transform_context(derived, context)
3044}
3045
3046struct MergedWorkspaceTransformContextV0 {
3047 context: TransformExecutionContextV0,
3048 style_fact_entries: Vec<OmenaQueryStyleFactEntry>,
3049}
3050
3051fn merge_workspace_transform_context_with_fact_entries(
3052 target_style_path: &str,
3053 style_sources: &[OmenaQueryStyleSourceInputV0],
3054 context: &TransformExecutionContextV0,
3055 resolution_context: TransformResolutionContext<'_>,
3056) -> MergedWorkspaceTransformContextV0 {
3057 let style_refs = style_sources
3058 .iter()
3059 .map(|source| (source.style_path.as_str(), source.style_source.as_str()))
3060 .collect::<Vec<_>>();
3061 let derived =
3062 context::derive_omena_query_transform_context_from_sources_with_resolution_context(
3063 target_style_path,
3064 style_refs,
3065 resolution_context,
3066 );
3067 MergedWorkspaceTransformContextV0 {
3068 context: merge_transform_context(derived.summary.context, context),
3069 style_fact_entries: derived.style_fact_entries,
3070 }
3071}
3072
3073pub fn list_omena_query_transform_pass_summaries() -> Vec<OmenaQueryTransformPassSummaryV0> {
3074 all_transform_pass_kinds()
3075 .into_iter()
3076 .map(|kind| OmenaQueryTransformPassSummaryV0 {
3077 id: kind.id(),
3078 title: kind.title(),
3079 reads_semantic_graph: kind.reads_semantic_graph(),
3080 reads_cascade_model: kind.reads_cascade_model(),
3081 explicit_opt_in_required: kind.explicit_opt_in_required(),
3082 dialect_restriction: kind.dialect_restriction(),
3083 spec_snapshot: kind.spec_snapshot(),
3084 opt_in_policy: kind.opt_in_policy(),
3085 })
3086 .collect()
3087}
3088
3089pub fn execute_omena_query_transform_passes_from_source_with_context(
3090 style_path: &str,
3091 style_source: &str,
3092 requested_pass_ids: &[String],
3093 context: &TransformExecutionContextV0,
3094) -> OmenaQueryTransformExecuteSummaryV0 {
3095 let context = merge_single_source_transform_context(style_path, style_source, context);
3096 if pass_ids_require_closed_world_bundle(requested_pass_ids)
3097 && let Some(closed_world_bundle) = build_closed_world_bundle_for_single_style_source_context(
3098 style_path,
3099 style_source,
3100 requested_pass_ids,
3101 &context,
3102 )
3103 {
3104 return execute_omena_query_transform_passes_from_source_with_context_and_closed_world_bundle(
3105 style_path,
3106 style_source,
3107 requested_pass_ids,
3108 &context,
3109 &closed_world_bundle,
3110 closed_world_bundle_reachability_precision(&context, &closed_world_bundle),
3111 &TransformExecutionPolicyV0::default(),
3112 );
3113 }
3114
3115 execute_omena_query_transform_passes_from_source_with_open_world_context(
3116 style_path,
3117 style_source,
3118 requested_pass_ids,
3119 &context,
3120 &TransformExecutionPolicyV0::default(),
3121 )
3122}
3123
3124fn execute_omena_query_transform_passes_from_source_with_open_world_context(
3125 style_path: &str,
3126 style_source: &str,
3127 requested_pass_ids: &[String],
3128 context: &TransformExecutionContextV0,
3129 execution_policy: &TransformExecutionPolicyV0,
3130) -> OmenaQueryTransformExecuteSummaryV0 {
3131 let (requested_passes, unknown_pass_ids) =
3132 requested_transform_passes_from_ids(requested_pass_ids);
3133
3134 let (admitted_passes, preflight_refusals) = strict_query_preflight(
3135 requested_pass_ids,
3136 requested_passes,
3137 execution_policy,
3138 false,
3139 );
3140 let expected_decision_count = admitted_passes.len();
3141
3142 let dialect = omena_parser_dialect_for_style_path(style_path);
3143 let mut execution = execute_transform_passes_on_source_with_dialect_context_and_policy(
3144 style_source,
3145 dialect,
3146 &admitted_passes,
3147 context,
3148 execution_policy,
3149 );
3150 merge_strict_preflight_refusals(&mut execution, preflight_refusals);
3151 enforce_strict_decision_coverage(&mut execution, execution_policy, expected_decision_count);
3152 let semantic_removal_count = execution.semantic_removals.len();
3153 let open_world_snapshot = open_world_snapshot_for_closed_world_passes(requested_pass_ids);
3154 let ready_surfaces = transform_execute_ready_surfaces_with_open_world_snapshot(
3155 open_world_snapshot.as_ref(),
3156 vec!["transformExecutionRuntime", "transformPassOutcomeContract"],
3157 );
3158
3159 OmenaQueryTransformExecuteSummaryV0 {
3160 schema_version: "0",
3161 product: "omena-query.transform-execute",
3162 style_path: style_path.to_string(),
3163 requested_pass_ids: requested_pass_ids.to_vec(),
3164 unknown_pass_ids,
3165 execution,
3166 semantic_removal_count,
3167 open_world_snapshot,
3168 ready_surfaces,
3169 }
3170}
3171
3172fn execute_omena_query_transform_passes_from_source_with_context_and_closed_world_bundle(
3173 style_path: &str,
3174 style_source: &str,
3175 requested_pass_ids: &[String],
3176 context: &TransformExecutionContextV0,
3177 closed_world_bundle: &ClosedWorldBundleV0,
3178 reachability_precision: FactPrecision,
3179 execution_policy: &TransformExecutionPolicyV0,
3180) -> OmenaQueryTransformExecuteSummaryV0 {
3181 let (requested_passes, unknown_pass_ids) =
3182 requested_transform_passes_from_ids(requested_pass_ids);
3183
3184 let (admitted_passes, preflight_refusals) =
3185 strict_query_preflight(requested_pass_ids, requested_passes, execution_policy, true);
3186 let expected_decision_count = admitted_passes.len();
3187
3188 let dialect = omena_parser_dialect_for_style_path(style_path);
3189 let mut execution = execute_transform_passes_on_source_with_dialect_context_closed_world_bundle_precision_and_policy(
3190 style_source,
3191 dialect,
3192 &admitted_passes,
3193 context,
3194 closed_world_bundle,
3195 reachability_precision,
3196 execution_policy,
3197 );
3198 merge_strict_preflight_refusals(&mut execution, preflight_refusals);
3199 enforce_strict_decision_coverage(&mut execution, execution_policy, expected_decision_count);
3200 let semantic_removal_count = execution.semantic_removals.len();
3201
3202 OmenaQueryTransformExecuteSummaryV0 {
3203 schema_version: "0",
3204 product: "omena-query.transform-execute",
3205 style_path: style_path.to_string(),
3206 requested_pass_ids: requested_pass_ids.to_vec(),
3207 unknown_pass_ids,
3208 execution,
3209 semantic_removal_count,
3210 open_world_snapshot: None,
3211 ready_surfaces: vec![
3212 "transformExecutionRuntime",
3213 "transformPassOutcomeContract",
3214 "closedWorldBundle",
3215 ],
3216 }
3217}
3218
3219fn execute_omena_query_transform_passes_from_module_with_context_and_closed_world_bundle(
3220 style_path: &str,
3221 style_source: &str,
3222 requested_pass_ids: &[String],
3223 context: &TransformExecutionContextV0,
3224 execution_inputs: ModuleQualifiedExecutionInputsV0<'_>,
3225 execution_policy: &TransformExecutionPolicyV0,
3226) -> Result<OmenaQueryTransformExecuteSummaryV0, TransformModuleQualifiedExecutionErrorV0> {
3227 let (requested_passes, unknown_pass_ids) =
3228 requested_transform_passes_from_ids(requested_pass_ids);
3229 let (admitted_passes, preflight_refusals) =
3230 strict_query_preflight(requested_pass_ids, requested_passes, execution_policy, true);
3231 let expected_decision_count = admitted_passes.len();
3232
3233 let dialect = omena_parser_dialect_for_style_path(style_path);
3234 let mut execution = if let Some(token_ownership_census) =
3235 execution_inputs.token_ownership_census
3236 {
3237 token_ownership_census
3238 .execute_module_transform_passes_with_ownership_admission_for_identity(
3239 style_source,
3240 dialect,
3241 &admitted_passes,
3242 context,
3243 execution_inputs.closed_world_bundle,
3244 execution_inputs.module_instance,
3245 execution_inputs.ownership_module_instance,
3246 execution_inputs.reachability_precision,
3247 execution_policy,
3248 execution_inputs.retained_class_names,
3249 )?
3250 } else {
3251 execute_transform_passes_on_module_with_dialect_context_policy_and_closed_world_bundle_and_retained_class_names(
3252 style_source,
3253 dialect,
3254 &admitted_passes,
3255 context,
3256 execution_inputs.closed_world_bundle,
3257 execution_inputs.module_instance,
3258 execution_inputs.reachability_precision,
3259 execution_policy,
3260 execution_inputs.retained_class_names,
3261 )?
3262 };
3263 merge_strict_preflight_refusals(&mut execution, preflight_refusals);
3264 enforce_strict_decision_coverage(&mut execution, execution_policy, expected_decision_count);
3265 let semantic_removal_count = execution.semantic_removals.len();
3266
3267 Ok(OmenaQueryTransformExecuteSummaryV0 {
3268 schema_version: "0",
3269 product: "omena-query.transform-execute",
3270 style_path: style_path.to_string(),
3271 requested_pass_ids: requested_pass_ids.to_vec(),
3272 unknown_pass_ids,
3273 execution,
3274 semantic_removal_count,
3275 open_world_snapshot: None,
3276 ready_surfaces: vec![
3277 "transformExecutionRuntime",
3278 "transformPassOutcomeContract",
3279 "closedWorldBundle",
3280 "moduleQualifiedReachability",
3281 ],
3282 })
3283}
3284
3285fn strict_query_preflight(
3286 requested_pass_ids: &[String],
3287 requested_passes: Vec<TransformPassKind>,
3288 execution_policy: &TransformExecutionPolicyV0,
3289 has_closed_world_bundle: bool,
3290) -> (Vec<TransformPassKind>, Vec<TransformStrictPolicyEventV0>) {
3291 let Some(policy) = execution_policy.strict_policy.as_ref() else {
3292 return (requested_passes, Vec::new());
3293 };
3294 let requirements = OmenaQueryBuildAdmissionRequirementsV0 {
3295 refuse_unknown_pass_ids: policy.refuse_unknown_pass_ids,
3296 require_closed_world_evidence: policy.require_closed_world_evidence,
3297 require_complete_decisions: policy.require_complete_decisions,
3298 };
3299 let refusals = summarize_omena_query_build_preflight_refusals(
3300 requested_pass_ids,
3301 has_closed_world_bundle,
3302 requirements,
3303 );
3304 let refused_pass_ids = refusals
3305 .iter()
3306 .map(|event| event.pass_id.as_str())
3307 .collect::<BTreeSet<_>>();
3308 let admitted_passes = requested_passes
3309 .into_iter()
3310 .filter(|pass| !refused_pass_ids.contains(pass.id()))
3311 .collect();
3312 (admitted_passes, refusals)
3313}
3314
3315pub fn summarize_omena_query_build_preflight_refusals(
3316 pass_ids: &[String],
3317 has_closed_world_bundle: bool,
3318 requirements: OmenaQueryBuildAdmissionRequirementsV0,
3319) -> Vec<TransformStrictPolicyEventV0> {
3320 let mut seen = BTreeSet::new();
3321 pass_ids
3322 .iter()
3323 .filter(|pass_id| seen.insert(pass_id.as_str()))
3324 .filter_map(|pass_id| match transform_pass_kind_from_id(pass_id) {
3325 None if requirements.refuse_unknown_pass_ids => Some(TransformStrictPolicyEventV0 {
3326 pass_id: pass_id.clone(),
3327 reasons: vec![TransformStrictPolicyReasonV0::UnknownPass],
3328 }),
3329 Some(pass)
3330 if requirements.require_closed_world_evidence
3331 && transform_pass_requires_closed_world_bundle(pass)
3332 && !has_closed_world_bundle =>
3333 {
3334 Some(TransformStrictPolicyEventV0 {
3335 pass_id: pass_id.clone(),
3336 reasons: vec![TransformStrictPolicyReasonV0::ClosedWorldEvidenceUnavailable],
3337 })
3338 }
3339 _ => None,
3340 })
3341 .collect()
3342}
3343
3344pub fn summarize_omena_query_build_decision_coverage_refusal(
3345 decision_coverage_complete: bool,
3346 requirements: OmenaQueryBuildAdmissionRequirementsV0,
3347) -> Option<TransformStrictPolicyEventV0> {
3348 (requirements.require_complete_decisions && !decision_coverage_complete).then(|| {
3349 TransformStrictPolicyEventV0 {
3350 pass_id: "execution-plan".to_string(),
3351 reasons: vec![TransformStrictPolicyReasonV0::DecisionCoverageIncomplete],
3352 }
3353 })
3354}
3355
3356fn merge_strict_preflight_refusals(
3357 execution: &mut TransformExecutionSummaryV0,
3358 refusals: Vec<TransformStrictPolicyEventV0>,
3359) {
3360 for refusal in refusals {
3361 execution
3362 .strict_policy
3363 .record_refusal(refusal.pass_id, refusal.reasons);
3364 }
3365}
3366
3367fn enforce_strict_decision_coverage(
3368 execution: &mut TransformExecutionSummaryV0,
3369 execution_policy: &TransformExecutionPolicyV0,
3370 expected_decision_count: usize,
3371) {
3372 let requirements = execution_policy
3373 .strict_policy
3374 .as_ref()
3375 .map(|policy| OmenaQueryBuildAdmissionRequirementsV0 {
3376 refuse_unknown_pass_ids: policy.refuse_unknown_pass_ids,
3377 require_closed_world_evidence: policy.require_closed_world_evidence,
3378 require_complete_decisions: policy.require_complete_decisions,
3379 })
3380 .unwrap_or_default();
3381 if let Some(refusal) = summarize_omena_query_build_decision_coverage_refusal(
3382 execution.decisions.len() == expected_decision_count,
3383 requirements,
3384 ) {
3385 execution
3386 .strict_policy
3387 .record_refusal(refusal.pass_id, refusal.reasons);
3388 }
3389}
3390
3391#[cfg(feature = "transform-catalog-trace")]
3392#[allow(deprecated)]
3393pub fn execute_omena_query_transform_passes_from_source_with_transform_catalog_trace(
3394 style_path: &str,
3395 style_source: &str,
3396 requested_pass_ids: &[String],
3397) -> OmenaQueryTransformCatalogTransformExecuteSummaryV0 {
3398 let execution = execute_omena_query_transform_passes_from_source(
3399 style_path,
3400 style_source,
3401 requested_pass_ids,
3402 );
3403 let requested_passes = requested_pass_ids
3404 .iter()
3405 .filter_map(|pass_id| transform_pass_kind_from_id(pass_id))
3406 .collect::<Vec<_>>();
3407 let dialect = omena_parser_dialect_for_style_path(style_path);
3408 let (_traced_execution, transform_catalog_trace) =
3409 execute_transform_passes_on_source_with_transform_catalog_trace_and_dialect(
3410 style_source,
3411 dialect,
3412 requested_passes.as_slice(),
3413 );
3414 let parallel_plan =
3415 plan_transform_passes_parallel_transform_catalog_layers(requested_passes.as_slice());
3416 let mut reorderability_certificates = Vec::new();
3417 let mut differential_witnesses = Vec::new();
3418
3419 if let Some((left, right)) = requested_passes.first().zip(requested_passes.get(1)) {
3420 let (certificate, witness) =
3421 evaluate_transform_catalog_reorderability_with_differential_corpus(
3422 *left,
3423 *right,
3424 &[style_source],
3425 );
3426 reorderability_certificates.push(certificate);
3427 differential_witnesses.push(witness);
3428 }
3429
3430 build_transform_catalog_execute_summary_v0(
3431 execution,
3432 transform_catalog_trace,
3433 parallel_plan,
3434 reorderability_certificates,
3435 differential_witnesses,
3436 )
3437}
3438
3439#[cfg(feature = "transform-catalog-trace")]
3440#[allow(deprecated)]
3441fn build_transform_catalog_execute_summary_v0(
3442 execution: OmenaQueryTransformExecuteSummaryV0,
3443 transform_catalog_trace: OmenaQueryTransformCatalogModelTraceV0,
3444 parallel_plan: OmenaQueryTransformCatalogTransformPassParallelPlanV0,
3445 reorderability_certificates: Vec<OmenaQueryTransformCatalogReorderabilityCertificateV0>,
3446 differential_witnesses: Vec<OmenaQueryTransformCatalogDifferentialCommutativityWitnessV0>,
3447) -> OmenaQueryTransformCatalogTransformExecuteSummaryV0 {
3448 build_transform_catalog_execute_summary_with_legacy_field_v0(
3449 execution,
3450 transform_catalog_trace,
3451 parallel_plan,
3452 reorderability_certificates,
3453 differential_witnesses,
3454 )
3455}
3456
3457#[cfg(feature = "transform-catalog-trace")]
3458#[allow(deprecated)]
3459#[deprecated(
3460 since = "0.4.0",
3461 note = "constructs a retained serialized field; owned by omena-query maintainers; removal is not before 1.0 and requires downstream migration plus zero audited non-compatibility uses"
3462)]
3463fn build_transform_catalog_execute_summary_with_legacy_field_v0(
3464 execution: OmenaQueryTransformExecuteSummaryV0,
3465 transform_catalog_trace: OmenaQueryTransformCatalogModelTraceV0,
3466 parallel_plan: OmenaQueryTransformCatalogTransformPassParallelPlanV0,
3467 reorderability_certificates: Vec<OmenaQueryTransformCatalogReorderabilityCertificateV0>,
3468 differential_witnesses: Vec<OmenaQueryTransformCatalogDifferentialCommutativityWitnessV0>,
3469) -> OmenaQueryTransformCatalogTransformExecuteSummaryV0 {
3470 OmenaQueryTransformCatalogTransformExecuteSummaryV0 {
3471 schema_version: "0",
3472 product: "omena-query.transform-execute-transform-catalog-trace",
3473 product_scope: "explicitOptInTransformCatalogTraceProductLane",
3474 default_product_mechanism: false,
3475 global_transform_theorem_claimed: false,
3476 execution,
3477 lawvere_trace: transform_catalog_trace,
3478 parallel_plan,
3479 reorderability_certificates,
3480 differential_witnesses,
3481 ready_surfaces: vec![
3482 "queryTransformExecutionHandoff",
3483 "transformCatalogModelTrace",
3484 "transformCatalogParallelPlanTrace",
3485 "transformCatalogDifferentialReorderabilityCertificate",
3486 ],
3487 }
3488}
3489
3490#[cfg(feature = "transform-catalog-trace")]
3491#[allow(deprecated)]
3492#[deprecated(
3493 since = "0.4.0",
3494 note = "use execute_omena_query_transform_passes_from_source_with_transform_catalog_trace; removal is not before 1.0 and requires downstream migration plus zero audited non-compatibility uses"
3495)]
3496pub fn execute_omena_query_transform_passes_from_source_with_lawvere_trace(
3497 style_path: &str,
3498 style_source: &str,
3499 requested_pass_ids: &[String],
3500) -> OmenaQueryLawvereTransformExecuteSummaryV0 {
3501 let execution = execute_omena_query_transform_passes_from_source(
3502 style_path,
3503 style_source,
3504 requested_pass_ids,
3505 );
3506 let requested_passes = requested_pass_ids
3507 .iter()
3508 .filter_map(|pass_id| transform_pass_kind_from_id(pass_id))
3509 .collect::<Vec<_>>();
3510 let dialect = omena_parser_dialect_for_style_path(style_path);
3511 let (_traced_execution, lawvere_trace) =
3512 omena_query_transform_runner::execute_transform_passes_on_source_with_lawvere_trace_and_dialect(
3513 style_source,
3514 dialect,
3515 requested_passes.as_slice(),
3516 );
3517 let parallel_plan = omena_query_transform_runner::plan_transform_passes_parallel_lawvere_layers(
3518 requested_passes.as_slice(),
3519 );
3520 let mut reorderability_certificates = Vec::new();
3521 let mut differential_witnesses = Vec::new();
3522 if let Some((left, right)) = requested_passes.first().zip(requested_passes.get(1)) {
3523 let (certificate, witness) =
3524 omena_query_transform_runner::evaluate_lawvere_reorderability_with_differential_corpus(
3525 *left,
3526 *right,
3527 &[style_source],
3528 );
3529 reorderability_certificates.push(certificate);
3530 differential_witnesses.push(witness);
3531 }
3532
3533 OmenaQueryLawvereTransformExecuteSummaryV0 {
3534 schema_version: "0",
3535 product: "omena-query.transform-execute-lawvere-trace",
3536 product_scope: "explicitOptInLawvereTraceProductLane",
3537 default_product_mechanism: false,
3538 global_transform_theorem_claimed: false,
3539 execution,
3540 lawvere_trace,
3541 parallel_plan,
3542 reorderability_certificates,
3543 differential_witnesses,
3544 ready_surfaces: vec![
3545 "queryTransformExecutionHandoff",
3546 "lawvereModelTrace",
3547 "lawvereParallelPlanTrace",
3548 "lawvereDifferentialReorderabilityCertificate",
3549 ],
3550 }
3551}
3552
3553pub fn summarize_omena_query_transform_context_from_sources<'a>(
3554 target_style_path: &str,
3555 styles: impl IntoIterator<Item = (&'a str, &'a str)>,
3556 package_manifests: &[OmenaQueryStylePackageManifestV0],
3557) -> OmenaQueryTransformContextFromSourcesSummaryV0 {
3558 let styles = styles.into_iter().collect::<Vec<_>>();
3559 let style_sources = styles
3560 .iter()
3561 .map(|(style_path, style_source)| OmenaQueryStyleSourceInputV0 {
3562 style_path: (*style_path).to_string(),
3563 style_source: (*style_source).to_string(),
3564 })
3565 .collect::<Vec<_>>();
3566 let resolution_inputs = resolution_inputs_for_transform_style_sources(
3567 target_style_path,
3568 style_sources.as_slice(),
3569 package_manifests,
3570 );
3571 summarize_omena_query_transform_context_from_sources_with_resolution_context(
3572 target_style_path,
3573 styles,
3574 TransformResolutionContext::from_resolution_inputs(&resolution_inputs),
3575 )
3576}
3577
3578pub fn summarize_omena_query_transform_context_from_sources_with_resolution_inputs<'a>(
3579 target_style_path: &str,
3580 styles: impl IntoIterator<Item = (&'a str, &'a str)>,
3581 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
3582) -> OmenaQueryTransformContextFromSourcesSummaryV0 {
3583 summarize_omena_query_transform_context_from_sources_with_resolution_context(
3584 target_style_path,
3585 styles,
3586 TransformResolutionContext::from_resolution_inputs(resolution_inputs),
3587 )
3588}
3589
3590fn apply_transform_source_replacements(
3591 source: &str,
3592 mut replacements: Vec<(usize, usize, String)>,
3593) -> (String, usize) {
3594 if replacements.is_empty() {
3595 return (source.to_string(), 0);
3596 }
3597 replacements.sort_by_key(|replacement| replacement.0);
3598 let mut output = source.to_string();
3599 let mut mutation_count = 0usize;
3600 for (start, end, replacement) in replacements.into_iter().rev() {
3601 if start > end || end > output.len() {
3602 continue;
3603 }
3604 output.replace_range(start..end, replacement.as_str());
3605 mutation_count += 1;
3606 }
3607 (output, mutation_count)
3608}
3609
3610fn transform_token_start(token: &omena_parser::LexedToken) -> usize {
3611 let start: u32 = token.range.start().into();
3612 start as usize
3613}
3614
3615fn transform_token_end(token: &omena_parser::LexedToken) -> usize {
3616 let end: u32 = token.range.end().into();
3617 end as usize
3618}
3619
3620fn extend_passes_from_ids(ids: &[&'static str], passes: &mut Vec<TransformPassKind>) {
3621 for candidate in all_transform_pass_kinds() {
3622 if ids.contains(&candidate.id()) && !passes.contains(&candidate) {
3623 passes.push(candidate);
3624 }
3625 }
3626}
3627
3628fn requested_transform_passes_from_ids(
3629 requested_pass_ids: &[String],
3630) -> (Vec<TransformPassKind>, Vec<String>) {
3631 let mut requested_passes = Vec::new();
3632 let mut unknown_pass_ids = Vec::new();
3633
3634 for pass_id in requested_pass_ids {
3635 match transform_pass_kind_from_id(pass_id) {
3636 Some(pass) => requested_passes.push(pass),
3637 None => unknown_pass_ids.push(pass_id.clone()),
3638 }
3639 }
3640
3641 (requested_passes, unknown_pass_ids)
3642}
3643
3644fn pass_ids_require_closed_world_bundle(pass_ids: &[String]) -> bool {
3645 pass_ids
3646 .iter()
3647 .filter_map(|pass_id| transform_pass_kind_from_id(pass_id))
3648 .any(transform_pass_requires_closed_world_bundle)
3649}
3650
3651fn open_world_snapshot_for_closed_world_passes(pass_ids: &[String]) -> Option<OpenWorldSnapshotV0> {
3652 if !pass_ids_require_closed_world_bundle(pass_ids) {
3653 return None;
3654 }
3655
3656 Some(OpenWorldSnapshotV0::new(format!(
3657 "closed-world bundle unavailable for requested passes: {}",
3658 pass_ids.join(", ")
3659 )))
3660}
3661
3662fn consumer_build_ready_surfaces_with_open_world_snapshot(
3663 snapshot: Option<&OpenWorldSnapshotV0>,
3664 mut ready_surfaces: Vec<&'static str>,
3665) -> Vec<&'static str> {
3666 if snapshot.is_some() && !ready_surfaces.contains(&"openWorldSnapshot") {
3667 ready_surfaces.push("openWorldSnapshot");
3668 }
3669 ready_surfaces
3670}
3671
3672fn extend_ready_surfaces(
3673 mut ready_surfaces: Vec<&'static str>,
3674 additions: impl IntoIterator<Item = &'static str>,
3675) -> Vec<&'static str> {
3676 for surface in additions {
3677 if !ready_surfaces.contains(&surface) {
3678 ready_surfaces.push(surface);
3679 }
3680 }
3681 ready_surfaces
3682}
3683
3684fn transform_execute_ready_surfaces_with_open_world_snapshot(
3685 snapshot: Option<&OpenWorldSnapshotV0>,
3686 ready_surfaces: Vec<&'static str>,
3687) -> Vec<&'static str> {
3688 consumer_build_ready_surfaces_with_open_world_snapshot(snapshot, ready_surfaces)
3689}
3690
3691fn requested_pass_ids_include_tree_shake(requested_pass_ids: &[String]) -> bool {
3692 requested_pass_ids
3693 .iter()
3694 .filter_map(|pass_id| transform_pass_kind_from_id(pass_id))
3695 .any(|pass| {
3696 matches!(
3697 pass,
3698 TransformPassKind::TreeShakeClass
3699 | TransformPassKind::TreeShakeKeyframes
3700 | TransformPassKind::TreeShakeValue
3701 | TransformPassKind::TreeShakeCustomProperty
3702 )
3703 })
3704}
3705
3706#[derive(Clone, Copy)]
3707struct ClosedWorldStylesheetRequestV0<'a> {
3708 target_style_path: &'a str,
3709 style_sources: &'a [OmenaQueryStyleSourceInputV0],
3710 requested_pass_ids: &'a [String],
3711 context: &'a TransformExecutionContextV0,
3712 reachability_context: &'a TransformExecutionContextV0,
3713 attribution_report: Option<&'a OmenaQueryModuleReachabilityAttributionReportV0>,
3714 resolution_inputs: &'a OmenaQueryStyleResolutionInputsV0,
3715 external_sifs: &'a [OmenaQueryExternalSifInputV0],
3716 source_set_closed: bool,
3717}
3718
3719fn build_closed_world_outcome_for_style_sources(
3720 request: ClosedWorldStylesheetRequestV0<'_>,
3721) -> OmenaQueryClosedWorldOutcomeV0 {
3722 closed_world_outcome_from_link_result(
3723 link_closed_world_stylesheet_for_style_sources(
3724 request,
3725 TransformBundleLinkOptionsV0::default(),
3726 )
3727 .into_requested_policy_result()
3728 .map(|linked| linked.linked_stylesheet),
3729 request.requested_pass_ids,
3730 )
3731}
3732
3733fn link_closed_world_stylesheet_for_style_sources(
3734 request: ClosedWorldStylesheetRequestV0<'_>,
3735 link_options: TransformBundleLinkOptionsV0,
3736) -> TransformBundleEmissionAdmissionV0 {
3737 let reachability_inputs = if requested_pass_ids_include_tree_shake(request.requested_pass_ids) {
3738 request
3739 .style_sources
3740 .iter()
3741 .map(|source| {
3742 transform_bundle_semantic_reachability_input_from_context_and_attribution(
3743 source.style_path.as_str(),
3744 request.reachability_context,
3745 request.attribution_report,
3746 )
3747 })
3748 .collect::<Vec<_>>()
3749 } else {
3750 Vec::new()
3751 };
3752 let prepared = prepare_transform_bundle_linker_projection(
3753 &[request.target_style_path],
3754 request.style_sources,
3755 reachability_inputs.as_slice(),
3756 TransformResolutionContext::from_resolution_inputs(request.resolution_inputs),
3757 );
3758 let module_metadata = style_sources_to_closed_world_metadata(
3759 &prepared.projection,
3760 request.context,
3761 request.external_sifs,
3762 request.source_set_closed,
3763 );
3764 evaluate_omena_transform_bundle_projection_emission_admission_with_resolved_dependencies_and_options(
3765 &[request.target_style_path],
3766 &prepared.projection,
3767 &prepared.emission_item_projection,
3768 prepared.resolved_dependencies.as_slice(),
3769 &module_metadata,
3770 link_options,
3771 )
3772}
3773
3774struct PreparedTransformBundleLinkerProjectionV0 {
3775 projection: TransformBundleLinkerProjectionV0,
3776 emission_item_projection: TransformBundleEmissionItemProjectionV0,
3777 resolved_dependencies: Vec<TransformBundleResolvedDependencyV0>,
3778 #[cfg(test)]
3779 expected_instance_reachability_count: usize,
3780 #[cfg(test)]
3781 emitted_instance_reachability_count: usize,
3782}
3783
3784struct TransformBundleDependencyResolutionTemplateV0 {
3785 source_path: String,
3786 edge_kind: TransformBundleEdgeKind,
3787 import_source: String,
3788 import_ordinal: Option<u32>,
3789 policy_step_keys: Vec<&'static str>,
3790 resolution_kind: &'static str,
3791 candidate_count: usize,
3792 target_source_path: Option<String>,
3793 target_configuration: omena_parser::ConfigurationHashV0,
3794}
3795
3796#[allow(deprecated)]
3797fn fan_out_reachability_to_instances(
3798 reachability_inputs: &[TransformBundleSemanticReachabilityInputV0],
3799 configurations_by_source_path: &BTreeMap<String, BTreeSet<omena_parser::ConfigurationHashV0>>,
3800) -> (Vec<TransformBundleInstanceReachabilityInputV0>, usize) {
3801 let mut reachability_by_path =
3802 BTreeMap::<String, TransformBundleSemanticReachabilityInputV0>::new();
3803 for input in reachability_inputs {
3804 let source_path = normalize_omena_transform_bundle_path(&input.source_path);
3805 let merged = reachability_by_path
3806 .entry(source_path.clone())
3807 .or_insert_with(|| TransformBundleSemanticReachabilityInputV0::new(source_path));
3808 merged.analysis = merge_query_reachability_analysis(merged.analysis, input.analysis);
3809 merged.class_names.extend(input.class_names.iter().cloned());
3810 merged
3811 .keyframe_names
3812 .extend(input.keyframe_names.iter().cloned());
3813 merged.value_names.extend(input.value_names.iter().cloned());
3814 merged
3815 .custom_property_names
3816 .extend(input.custom_property_names.iter().cloned());
3817 merged.class_names.sort();
3818 merged.class_names.dedup();
3819 merged.keyframe_names.sort();
3820 merged.keyframe_names.dedup();
3821 merged.value_names.sort();
3822 merged.value_names.dedup();
3823 merged.custom_property_names =
3824 dedupe_custom_property_names(merged.custom_property_names.drain(..));
3825 }
3826
3827 let expected_instance_reachability_count = reachability_by_path
3828 .keys()
3829 .filter_map(|source_path| configurations_by_source_path.get(source_path))
3830 .map(BTreeSet::len)
3831 .sum();
3832 let instance_reachability_inputs = reachability_by_path
3833 .into_iter()
3834 .flat_map(|(source_path, reachability)| {
3835 configurations_by_source_path
3836 .get(&source_path)
3837 .into_iter()
3838 .flatten()
3839 .map(move |configuration| {
3840 let mut input = TransformBundleInstanceReachabilityInputV0::new(
3841 omena_parser::ModuleInstanceKeyV0::new(
3842 omena_parser::ModuleIdV0::new(source_path.clone()),
3843 configuration.clone(),
3844 ),
3845 InstanceReachabilityDerivationV0::PathUnionNoInstanceDiscriminator,
3846 );
3847 input.class_names.clone_from(&reachability.class_names);
3848 input
3849 .keyframe_names
3850 .clone_from(&reachability.keyframe_names);
3851 input.value_names.clone_from(&reachability.value_names);
3852 input
3853 .custom_property_names
3854 .clone_from(&reachability.custom_property_names);
3855 input.analysis = reachability.analysis;
3856 input
3857 })
3858 })
3859 .collect::<Vec<_>>();
3860
3861 (
3862 instance_reachability_inputs,
3863 expected_instance_reachability_count,
3864 )
3865}
3866
3867fn merge_query_reachability_analysis(
3868 current: TransformBundleReachabilityAnalysisV0,
3869 incoming: TransformBundleReachabilityAnalysisV0,
3870) -> TransformBundleReachabilityAnalysisV0 {
3871 match (current, incoming) {
3872 (TransformBundleReachabilityAnalysisV0::Analyzed, next) => next,
3873 (unavailable @ TransformBundleReachabilityAnalysisV0::Unanalyzed { .. }, _) => unavailable,
3874 _ => TransformBundleReachabilityAnalysisV0::Unanalyzed {
3875 cause: TransformBundleReachabilityUnanalyzedCauseV0::AnalysisResultUnavailable,
3876 },
3877 }
3878}
3879
3880#[allow(deprecated)]
3881fn prepare_transform_bundle_linker_projection(
3882 entrypoint_paths: &[&str],
3883 style_sources: &[OmenaQueryStyleSourceInputV0],
3884 reachability_inputs: &[TransformBundleSemanticReachabilityInputV0],
3885 resolution_context: TransformResolutionContext<'_>,
3886) -> PreparedTransformBundleLinkerProjectionV0 {
3887 let mut modules = style_sources_to_transform_bundle_modules(style_sources);
3888 let provisional_projection =
3889 project_omena_transform_bundle_linker_inputs_from_parsed_modules(&modules, &[]);
3890 let (templates, mut configurations_by_source_path) =
3891 resolve_transform_bundle_projection_dependency_templates(
3892 &provisional_projection,
3893 modules.as_slice(),
3894 style_sources,
3895 resolution_context,
3896 );
3897 let projection_path_by_source_path =
3898 projection_path_by_source_path(modules.as_slice(), style_sources);
3899 for entrypoint_path in entrypoint_paths {
3900 if let Some(projection_path) = projection_path_by_source_path.get(*entrypoint_path) {
3901 configurations_by_source_path
3902 .entry(projection_path.clone())
3903 .or_default()
3904 .insert(omena_parser::ConfigurationHashV0::none());
3905 }
3906 }
3907 for configurations in configurations_by_source_path.values_mut() {
3908 if configurations.is_empty() {
3909 configurations.insert(omena_parser::ConfigurationHashV0::none());
3910 }
3911 }
3912 let (instance_reachability_inputs, expected_instance_reachability_count) =
3913 fan_out_reachability_to_instances(reachability_inputs, &configurations_by_source_path);
3914 let emitted_instance_reachability_count = instance_reachability_inputs.len();
3915 #[cfg(not(test))]
3916 let _ = (
3917 expected_instance_reachability_count,
3918 emitted_instance_reachability_count,
3919 );
3920
3921 modules = modules
3922 .into_iter()
3923 .map(|module| {
3924 let projection_path = module
3925 .module_instance_keys()
3926 .into_iter()
3927 .next()
3928 .map(|instance| instance.module().as_str().to_string())
3929 .unwrap_or_else(|| module.source_path().to_string());
3930 let configurations = configurations_by_source_path
3931 .remove(&projection_path)
3932 .unwrap_or_else(|| BTreeSet::from([omena_parser::ConfigurationHashV0::none()]))
3933 .into_iter()
3934 .collect();
3935 module.with_configuration_hashes(configurations)
3936 })
3937 .collect();
3938
3939 let projections =
3940 project_omena_transform_bundle_linker_and_emission_items_from_parsed_modules_with_instance_reachability(
3941 modules.as_slice(),
3942 instance_reachability_inputs.as_slice(),
3943 );
3944 let projection = projections.linker_projection().clone();
3945 let resolved_dependencies =
3946 materialize_transform_bundle_resolved_dependencies(&projection, templates);
3947 PreparedTransformBundleLinkerProjectionV0 {
3948 projection,
3949 emission_item_projection: projections.emission_item_projection().clone(),
3950 resolved_dependencies,
3951 #[cfg(test)]
3952 expected_instance_reachability_count,
3953 #[cfg(test)]
3954 emitted_instance_reachability_count,
3955 }
3956}
3957
3958fn resolve_transform_bundle_projection_dependency_templates(
3959 projection: &TransformBundleLinkerProjectionV0,
3960 modules: &[TransformBundleParsedModuleInputV0],
3961 style_sources: &[OmenaQueryStyleSourceInputV0],
3962 resolution_context: TransformResolutionContext<'_>,
3963) -> (
3964 Vec<TransformBundleDependencyResolutionTemplateV0>,
3965 BTreeMap<String, BTreeSet<omena_parser::ConfigurationHashV0>>,
3966) {
3967 let available_style_paths = style_sources
3968 .iter()
3969 .map(|source| source.style_path.as_str())
3970 .collect::<BTreeSet<_>>();
3971 let projection_path_by_source_path = projection_path_by_source_path(modules, style_sources);
3972 let source_by_projection_path = modules
3973 .iter()
3974 .zip(style_sources)
3975 .filter_map(|(module, source)| {
3976 module
3977 .module_instance_keys()
3978 .into_iter()
3979 .next()
3980 .map(|instance| {
3981 (
3982 instance.module().as_str().to_string(),
3983 source.style_source.as_str(),
3984 )
3985 })
3986 })
3987 .collect::<BTreeMap<_, _>>();
3988 let mut configurations_by_source_path = projection
3989 .inputs()
3990 .iter()
3991 .map(|input| (input.source_path.clone(), BTreeSet::new()))
3992 .collect::<BTreeMap<_, _>>();
3993 let policy_step_keys = summarize_omena_query_style_resolution_policy_v0()
3994 .steps
3995 .into_iter()
3996 .map(|step| step.key)
3997 .collect::<Vec<_>>();
3998 let mut templates = Vec::new();
3999 for input in projection.inputs() {
4000 let source = source_by_projection_path
4001 .get(input.source_path.as_str())
4002 .copied()
4003 .unwrap_or_default();
4004 let mut sass_use_ordinal = 0usize;
4005 let mut sass_forward_ordinal = 0usize;
4006 for edge in &input.dependency_edges {
4007 let target_configuration = match edge.kind {
4008 TransformBundleEdgeKind::SassUse => {
4009 let overrides =
4010 omena_semantic::derive_sass_module_rule_variable_overrides_at_ordinal(
4011 source,
4012 "@use",
4013 sass_use_ordinal,
4014 );
4015 sass_use_ordinal += 1;
4016 omena_parser::ConfigurationHashV0::new(
4017 omena_semantic::summarize_sass_module_configuration_signature(&overrides),
4018 )
4019 }
4020 TransformBundleEdgeKind::SassForward => {
4021 let overrides =
4022 omena_semantic::derive_sass_module_forward_variable_override_values_at_ordinal(
4023 source,
4024 sass_forward_ordinal,
4025 );
4026 sass_forward_ordinal += 1;
4027 omena_parser::ConfigurationHashV0::new(
4028 omena_semantic::summarize_sass_module_configuration_signature(&overrides),
4029 )
4030 }
4031 _ => omena_parser::ConfigurationHashV0::none(),
4032 };
4033 let resolution = resolution_context.resolve_style_module(
4034 input.source_path.as_str(),
4035 edge.import_source.as_str(),
4036 &available_style_paths,
4037 );
4038 let target_source_path = resolution
4039 .resolved_style_path
4040 .as_deref()
4041 .and_then(|path| projection_path_by_source_path.get(path))
4042 .cloned();
4043 if let Some(target_source_path) = target_source_path.as_ref() {
4044 configurations_by_source_path
4045 .entry(target_source_path.clone())
4046 .or_default()
4047 .insert(target_configuration.clone());
4048 }
4049 templates.push(TransformBundleDependencyResolutionTemplateV0 {
4050 source_path: input.source_path.clone(),
4051 edge_kind: edge.kind,
4052 import_source: edge.import_source.clone(),
4053 import_ordinal: edge.import_ordinal,
4054 policy_step_keys: policy_step_keys.clone(),
4055 resolution_kind: resolution.resolution_kind,
4056 candidate_count: resolution.candidate_count,
4057 target_source_path,
4058 target_configuration,
4059 });
4060 }
4061 }
4062 (templates, configurations_by_source_path)
4063}
4064
4065fn projection_path_by_source_path(
4066 modules: &[TransformBundleParsedModuleInputV0],
4067 style_sources: &[OmenaQueryStyleSourceInputV0],
4068) -> BTreeMap<String, String> {
4069 let mut projection_path_by_source_path = BTreeMap::new();
4070 for (module, source) in modules.iter().zip(style_sources) {
4071 let Some(instance) = module.module_instance_keys().into_iter().next() else {
4072 continue;
4073 };
4074 let projection_path = instance.module().as_str().to_string();
4075 projection_path_by_source_path.insert(source.style_path.clone(), projection_path.clone());
4076 projection_path_by_source_path.insert(projection_path.clone(), projection_path);
4077 }
4078 projection_path_by_source_path
4079}
4080
4081fn materialize_transform_bundle_resolved_dependencies(
4082 projection: &TransformBundleLinkerProjectionV0,
4083 templates: Vec<TransformBundleDependencyResolutionTemplateV0>,
4084) -> Vec<TransformBundleResolvedDependencyV0> {
4085 let instance_by_path_and_configuration = projection
4086 .inputs()
4087 .iter()
4088 .map(|input| {
4089 (
4090 (
4091 input.source_path.as_str(),
4092 input.instance.configuration().as_str(),
4093 ),
4094 input.instance.clone(),
4095 )
4096 })
4097 .collect::<BTreeMap<_, _>>();
4098 let source_instances_by_path = projection.inputs().iter().fold(
4099 BTreeMap::<&str, Vec<omena_parser::ModuleInstanceKeyV0>>::new(),
4100 |mut by_path, input| {
4101 by_path
4102 .entry(input.source_path.as_str())
4103 .or_default()
4104 .push(input.instance.clone());
4105 by_path
4106 },
4107 );
4108 let mut resolved_dependencies = Vec::new();
4109 for template in templates {
4110 let target_instance = template.target_source_path.as_deref().and_then(|path| {
4111 instance_by_path_and_configuration
4112 .get(&(path, template.target_configuration.as_str()))
4113 .cloned()
4114 });
4115 let Some(source_instances) = source_instances_by_path.get(template.source_path.as_str())
4116 else {
4117 continue;
4118 };
4119 for source_instance in source_instances {
4120 resolved_dependencies.push(TransformBundleResolvedDependencyV0::new(
4121 source_instance.clone(),
4122 template.edge_kind,
4123 template.import_source.as_str(),
4124 template.import_ordinal,
4125 TransformBundleDependencyResolutionV0::attempted(
4126 template.policy_step_keys.clone(),
4127 template.resolution_kind,
4128 template.candidate_count,
4129 target_instance.clone(),
4130 ),
4131 ));
4132 }
4133 }
4134 resolved_dependencies
4135}
4136
4137#[allow(clippy::too_many_arguments)]
4138fn execute_linked_bundle_modules(
4139 linked: &LinkedStylesheetWithEmissionItemsV0,
4140 target_style_path: &str,
4141 module_inputs: &[LinkedModuleExecutionInputV0<'_>],
4142 retained_class_names_by_module: &BTreeMap<omena_parser::ModuleInstanceKeyV0, Vec<String>>,
4143 pass_set: &ConsumerBuildPassSetV0,
4144 token_ownership_census: Option<&CssModuleTokenOwnershipCensusV0>,
4145 options: &OmenaQueryConsumerBuildOptionsV0,
4146) -> Result<LinkedBundleExecutionV0, String> {
4147 let linked_stylesheet = &linked.linked_stylesheet;
4148 let target_instance = linked_stylesheet
4149 .entrypoints
4150 .first()
4151 .ok_or_else(|| format!("linked bundle has no entrypoint for {target_style_path:?}"))?;
4152 let mut transformed_modules = Vec::with_capacity(linked_stylesheet.module_instances.len());
4153 let mut module_executions = Vec::with_capacity(linked_stylesheet.module_instances.len());
4154
4155 for module_input in module_inputs {
4156 let module_instance = module_input.module_instance;
4157 let style_path = module_instance.module().as_str();
4158 let class_name_rewrites = if pass_set
4159 .effective
4160 .iter()
4161 .any(|pass_id| TransformPassKind::HashCssModuleClassNames.id() == pass_id)
4162 {
4163 module_input.context.class_name_rewrites.clone()
4164 } else {
4165 Vec::new()
4166 };
4167 let retained_class_names = retained_class_names_by_module
4168 .get(module_instance)
4169 .map(Vec::as_slice)
4170 .unwrap_or_default();
4171 let execution_inputs = ModuleQualifiedExecutionInputsV0 {
4172 closed_world_bundle: &linked_stylesheet.closed_world_bundle,
4173 module_instance,
4174 ownership_module_instance: &module_input.ownership_module_instance,
4175 reachability_precision: closed_world_bundle_reachability_precision(
4176 &module_input.context,
4177 &linked_stylesheet.closed_world_bundle,
4178 ),
4179 retained_class_names,
4180 token_ownership_census,
4181 };
4182 let summary =
4183 execute_omena_query_consumer_build_style_module_with_context_and_closed_world_bundle(
4184 style_path,
4185 module_input.style_source.as_str(),
4186 pass_set,
4187 &module_input.context,
4188 execution_inputs,
4189 options,
4190 )?;
4191 let execution = summary.execution;
4192 let non_empty_import_replacement_count = execution
4193 .css_import_inlines
4194 .iter()
4195 .filter(|inline| !inline.replacement_css.is_empty())
4196 .count();
4197 transformed_modules.push(
4198 TransformBundleTransformedModuleV0::new(
4199 module_instance.clone(),
4200 execution.output_css.clone(),
4201 )
4202 .with_non_empty_import_replacement_count(non_empty_import_replacement_count),
4203 );
4204 module_executions.push(LinkedModuleExecutionV0 {
4205 module_instance: module_instance.clone(),
4206 execution,
4207 class_name_rewrites,
4208 });
4209 }
4210
4211 let materialized = materialize_omena_transform_bundle_linked_stylesheet_with_emission_items(
4212 linked,
4213 &transformed_modules,
4214 )
4215 .map_err(|error| format!("linked bundle materialization failed: {error:?}"))?;
4216 let Some(entry_execution) = module_executions
4217 .iter()
4218 .find(|module| &module.module_instance == target_instance)
4219 .map(|module| module.execution.clone())
4220 else {
4221 return Err(format!(
4222 "linked entrypoint {target_style_path:?} was not transformed"
4223 ));
4224 };
4225 #[allow(deprecated)]
4226 let execution =
4227 project_linked_bundle_execution(entry_execution, materialized.output_css.as_str());
4228 Ok(LinkedBundleExecutionV0 {
4229 execution,
4230 entry_module_instance: target_instance.clone(),
4231 module_executions,
4232 materialization: materialized,
4233 asset_rewrites: Vec::new(),
4234 })
4235}
4236
4237#[allow(clippy::too_many_arguments)]
4238fn execute_linked_bundle_modules_with_ownership_reference(
4239 linked: &LinkedStylesheetWithEmissionItemsV0,
4240 target_style_path: &str,
4241 style_sources: &[OmenaQueryStyleSourceInputV0],
4242 style_fact_entries: &[OmenaQueryStyleFactEntry],
4243 effective_pass_ids: &[String],
4244 base_context: &TransformExecutionContextV0,
4245 module_css_module_contexts: &[TransformModuleCssModuleContextV0],
4246 module_identity_root: Option<&str>,
4247 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
4248 pre_rewritten_asset_sources: &[TransformBundleAssetUrlRewriteSummaryV0],
4249 options: &OmenaQueryConsumerBuildOptionsV0,
4250) -> Result<LinkedBundleExecutionV0, String> {
4251 let linked_stylesheet = &linked.linked_stylesheet;
4252 let pass_set = consumer_build_pass_set(effective_pass_ids);
4253 let resolution_context = TransformResolutionContext::from_resolution_inputs(resolution_inputs);
4254 let normalized_module_css_module_contexts = module_css_module_contexts
4255 .iter()
4256 .map(|context| {
4257 let mut context = context.clone();
4258 if let Some(root) = module_identity_root {
4259 context.module_instance = css_modules::module_instance_key_relative_to_root(
4260 &context.module_instance,
4261 root,
4262 )?;
4263 }
4264 Ok(context)
4265 })
4266 .collect::<Result<Vec<_>, String>>()?;
4267
4268 let mut module_inputs = Vec::with_capacity(linked_stylesheet.module_instances.len());
4269 let mut asset_rewrites = Vec::new();
4270 for module_instance in &linked_stylesheet.module_instances {
4271 let style_path = module_instance.module().as_str();
4272 let Some(style_source) = find_target_style_source(style_path, style_sources) else {
4273 return Err(format!(
4274 "linked module {style_path:?} was not found in workspace style sources"
4275 ));
4276 };
4277 let mut module_context = merge_workspace_transform_context(
4278 style_path,
4279 style_sources,
4280 base_context,
4281 resolution_context,
4282 );
4283 let token_module_instance = module_identity_root.map_or_else(
4284 || Ok(module_instance.clone()),
4285 |root| css_modules::module_instance_key_relative_to_root(module_instance, root),
4286 )?;
4287 let module_fact_entry = collect_omena_query_style_fact_entry(style_path, style_source);
4288 module_context.class_name_rewrites = derive_class_name_rewrites_for_module_instance(
4289 &module_fact_entry,
4290 &token_module_instance,
4291 );
4292 let derived_module_context =
4293 TransformModuleCssModuleContextV0::new(token_module_instance.clone())
4294 .with_class_name_rewrites(module_context.class_name_rewrites.clone())
4295 .with_composes_resolutions(module_context.css_module_composes_resolutions.clone());
4296 let selected_module_contexts = context::merge_module_css_module_contexts_first_witness(
4297 &normalized_module_css_module_contexts,
4298 &[derived_module_context],
4299 );
4300 if let Some(selected) = selected_module_contexts
4301 .iter()
4302 .find(|selected| selected.module_instance == token_module_instance)
4303 {
4304 module_context.class_name_rewrites = selected.class_name_rewrites.clone();
4305 module_context.css_module_composes_resolutions = selected.composes_resolutions.clone();
4306 }
4307 for inline in &mut module_context.import_inlines {
4308 inline.replacement_css.clear();
4309 }
4310 let source_was_pre_rewritten = pre_rewritten_asset_sources.iter().any(|rewrite| {
4311 normalize_omena_transform_bundle_path(rewrite.source_path.as_str())
4312 == normalize_omena_transform_bundle_path(style_path)
4313 });
4314 let execution_source = if source_was_pre_rewritten {
4315 style_source.to_string()
4316 } else {
4317 let rewrite =
4318 rewrite_omena_transform_bundle_asset_urls_in_source(style_path, style_source);
4319 let output_css = rewrite.output_css.clone();
4320 asset_rewrites.push(rewrite);
4321 output_css
4322 };
4323 module_inputs.push(LinkedModuleExecutionInputV0 {
4324 module_instance,
4325 ownership_module_instance: token_module_instance,
4326 style_source: execution_source,
4327 context: module_context,
4328 });
4329 }
4330 let retained_class_names_by_module = retained_class_names_for_live_linked_emission_tokens(
4331 &linked_stylesheet.closed_world_bundle,
4332 module_inputs.as_slice(),
4333 );
4334
4335 let ownership_reference = if pass_set
4336 .effective
4337 .iter()
4338 .any(|pass_id| pass_id_is_fact_consuming(pass_id))
4339 {
4340 let reference_pass_ids = pass_set
4341 .effective
4342 .iter()
4343 .filter(|pass_id| !pass_id_is_fact_consuming(pass_id))
4344 .cloned()
4345 .collect::<Vec<_>>();
4346 let reference_pass_set = ConsumerBuildPassSetV0 {
4347 requested: reference_pass_ids.clone(),
4348 effective: reference_pass_ids,
4349 };
4350 let reference_execution = execute_linked_bundle_modules(
4351 linked,
4352 target_style_path,
4353 module_inputs.as_slice(),
4354 &retained_class_names_by_module,
4355 &reference_pass_set,
4356 None,
4357 options,
4358 )?;
4359 Some(
4360 token_integrity::summarize_css_module_token_ownership(
4361 target_style_path,
4362 style_fact_entries,
4363 linked,
4364 base_context,
4365 Some(reference_execution.module_executions.as_slice()),
4366 module_identity_root,
4367 options.bundle_emission_path,
4368 reference_execution.execution.output_css.as_str(),
4369 )
4370 .unwrap_or_else(|error| {
4371 token_integrity::unavailable_css_module_token_ownership_census(
4372 options.bundle_emission_path,
4373 error,
4374 )
4375 }),
4376 )
4377 } else {
4378 None
4379 };
4380
4381 let mut execution = execute_linked_bundle_modules(
4382 linked,
4383 target_style_path,
4384 module_inputs.as_slice(),
4385 &retained_class_names_by_module,
4386 &pass_set,
4387 ownership_reference.as_ref(),
4388 options,
4389 )?;
4390 execution.asset_rewrites = asset_rewrites;
4391 Ok(execution)
4392}
4393
4394fn pass_id_is_fact_consuming(pass_id: &str) -> bool {
4395 [
4396 TransformPassKind::TreeShakeClass,
4397 TransformPassKind::TreeShakeKeyframes,
4398 TransformPassKind::TreeShakeValue,
4399 TransformPassKind::TreeShakeCustomProperty,
4400 ]
4401 .into_iter()
4402 .any(|pass| pass.id() == pass_id)
4403}
4404
4405#[deprecated(
4406 note = "use BundleExecutionSummaryV0 from linked bundle execution-scope evidence; the compatibility projection remains wire-stable until a future major release"
4407)]
4408fn project_linked_bundle_execution(
4409 mut execution: TransformExecutionSummaryV0,
4410 materialized_output_css: &str,
4411) -> TransformExecutionSummaryV0 {
4412 execution.output_byte_len = materialized_output_css.len();
4413 execution.output_css = materialized_output_css.to_string();
4414 execution
4415}
4416
4417#[derive(Clone)]
4418struct LinkedModuleExecutionV0 {
4419 module_instance: omena_parser::ModuleInstanceKeyV0,
4420 execution: TransformExecutionSummaryV0,
4421 class_name_rewrites: Vec<TransformClassNameRewriteV0>,
4422}
4423
4424struct LinkedModuleExecutionInputV0<'a> {
4425 module_instance: &'a omena_parser::ModuleInstanceKeyV0,
4426 ownership_module_instance: omena_parser::ModuleInstanceKeyV0,
4427 style_source: String,
4428 context: TransformExecutionContextV0,
4429}
4430
4431fn retained_class_names_for_live_linked_emission_tokens(
4432 closed_world_bundle: &ClosedWorldBundleV0,
4433 module_inputs: &[LinkedModuleExecutionInputV0<'_>],
4434) -> BTreeMap<omena_parser::ModuleInstanceKeyV0, Vec<String>> {
4435 let mut live_emitted_tokens = BTreeSet::new();
4440 for module_input in module_inputs {
4441 let Some(symbols) = closed_world_bundle
4442 .reachability()
4443 .symbols_for_module(module_input.module_instance)
4444 else {
4445 continue;
4446 };
4447 for class_name in symbols.class_names() {
4448 let emitted_token = module_input
4449 .context
4450 .class_name_rewrites
4451 .iter()
4452 .find(|rewrite| {
4453 css_identifier_names_match(rewrite.original_name.as_str(), class_name)
4454 })
4455 .map_or(class_name.as_str(), |rewrite| {
4456 rewrite.rewritten_name.as_str()
4457 });
4458 live_emitted_tokens.insert(emitted_token.to_string());
4459 }
4460 }
4461
4462 module_inputs
4463 .iter()
4464 .map(|module_input| {
4465 let own_reachable = closed_world_bundle
4466 .reachability()
4467 .symbols_for_module(module_input.module_instance)
4468 .map(|symbols| symbols.class_names())
4469 .unwrap_or_default();
4470 let retained = if css_modules::style_path_is_css_module_path(
4471 module_input.module_instance.module().as_str(),
4472 ) {
4473 module_input
4474 .context
4475 .class_name_rewrites
4476 .iter()
4477 .filter(|rewrite| live_emitted_tokens.contains(&rewrite.rewritten_name))
4478 .map(|rewrite| rewrite.original_name.clone())
4479 .collect::<BTreeSet<_>>()
4480 } else {
4481 live_emitted_tokens.clone()
4482 }
4483 .into_iter()
4484 .filter(|name| {
4485 !own_reachable
4486 .iter()
4487 .any(|own| css_identifier_names_match(own, name))
4488 })
4489 .collect::<Vec<_>>();
4490 (module_input.module_instance.clone(), retained)
4491 })
4492 .collect()
4493}
4494
4495#[derive(Clone)]
4496struct LinkedBundleExecutionV0 {
4497 execution: TransformExecutionSummaryV0,
4498 entry_module_instance: omena_parser::ModuleInstanceKeyV0,
4499 module_executions: Vec<LinkedModuleExecutionV0>,
4500 materialization: LinkedEmissionArtifactV0,
4501 asset_rewrites: Vec<TransformBundleAssetUrlRewriteSummaryV0>,
4502}
4503
4504fn summarize_bundle_execution(linked: &LinkedBundleExecutionV0) -> BundleExecutionSummaryV0 {
4505 let mut aggregate_executed_pass_ids = Vec::new();
4506 let mut seen_executed_pass_ids = BTreeSet::new();
4507 for pass_id in linked
4508 .module_executions
4509 .iter()
4510 .flat_map(|module| module.execution.executed_pass_ids.iter().copied())
4511 {
4512 if seen_executed_pass_ids.insert(pass_id) {
4513 aggregate_executed_pass_ids.push(pass_id);
4514 }
4515 }
4516
4517 BundleExecutionSummaryV0 {
4518 schema_version: "0",
4519 product: "omena-query.bundle-execution",
4520 entry_module_instance: linked.entry_module_instance.clone(),
4521 module_executions: linked
4522 .module_executions
4523 .iter()
4524 .map(|module| BundleModuleExecutionV0 {
4525 module_instance: module.module_instance.clone(),
4526 execution: module.execution.clone(),
4527 })
4528 .collect(),
4529 emission_execution: BundleEmissionExecutionV0 {
4530 module_regions: linked.materialization.module_regions.clone(),
4531 order_entry_regions: linked.materialization.order_entry_regions.clone(),
4532 emitted_module_count: linked.materialization.emitted_module_count,
4533 global_order_entry_count: linked.materialization.global_order_entry_count,
4534 },
4535 aggregate_mutation_count: linked
4536 .module_executions
4537 .iter()
4538 .map(|module| module.execution.mutation_count)
4539 .sum(),
4540 aggregate_executed_pass_ids,
4541 aggregate_semantic_removal_count: linked
4542 .module_executions
4543 .iter()
4544 .map(|module| module.execution.semantic_removals.len())
4545 .sum(),
4546 aggregate_closed_world_refusal_count: linked
4547 .module_executions
4548 .iter()
4549 .map(|module| module.execution.closed_world_admission.refused_count)
4550 .sum(),
4551 }
4552}
4553
4554fn summarize_linked_bundle_execution_scope(
4555 linked: &LinkedBundleExecutionV0,
4556) -> Result<OmenaQueryBundleExecutionScopeEvidenceV0, String> {
4557 let mut module_executions = Vec::with_capacity(linked.module_executions.len());
4558 for module in &linked.module_executions {
4559 let region = linked
4560 .materialization
4561 .module_regions
4562 .iter()
4563 .find(|region| region.module_instance == module.module_instance)
4564 .ok_or_else(|| {
4565 format!(
4566 "linked execution evidence has no materialized region for {:?}",
4567 module.module_instance
4568 )
4569 })?;
4570 let generated_len = region.generated_end.saturating_sub(region.generated_start);
4571 if generated_len != module.execution.output_byte_len {
4572 return Err(format!(
4573 "linked execution evidence byte mismatch for {:?}: execution={}, materialized={generated_len}",
4574 module.module_instance, module.execution.output_byte_len
4575 ));
4576 }
4577 module_executions.push(OmenaQueryBundleModuleExecutionByteFactsV0 {
4578 module_instance: module.module_instance.clone(),
4579 input_byte_len: module.execution.input_byte_len,
4580 output_byte_len: module.execution.output_byte_len,
4581 generated_start: region.generated_start,
4582 generated_end: region.generated_end,
4583 });
4584 }
4585
4586 if module_executions.len() != linked.materialization.module_regions.len() {
4587 return Err(format!(
4588 "linked execution evidence cardinality mismatch: executions={}, regions={}",
4589 module_executions.len(),
4590 linked.materialization.module_regions.len()
4591 ));
4592 }
4593 let summed_module_input_byte_len = module_executions
4594 .iter()
4595 .map(|module| module.input_byte_len)
4596 .sum();
4597 let summed_module_output_byte_len = module_executions
4598 .iter()
4599 .map(|module| module.output_byte_len)
4600 .sum::<usize>();
4601 let materialized_output_byte_len = linked.materialization.output_css.len();
4602 let inter_module_separator_byte_len =
4603 linked_materialization_separator_byte_len(&linked.materialization)?;
4604 if summed_module_output_byte_len + inter_module_separator_byte_len
4605 != materialized_output_byte_len
4606 {
4607 return Err(
4608 "linked execution evidence could not account for bundle output bytes".to_string(),
4609 );
4610 }
4611
4612 Ok(OmenaQueryBundleExecutionScopeEvidenceV0 {
4613 schema_version: "0",
4614 product: "omena-query.bundle-execution-scope",
4615 entry_module_instance: linked.entry_module_instance.clone(),
4616 field_scopes: bundle_execution_field_scopes(),
4617 bundle_composite: OmenaQueryBundleCompositeExecutionByteFactsV0 {
4618 module_count: module_executions.len(),
4619 summed_module_input_byte_len,
4620 summed_module_output_byte_len,
4621 inter_module_separator_byte_len,
4622 materialized_output_byte_len,
4623 },
4624 bundle_execution: summarize_bundle_execution(linked),
4625 module_executions,
4626 source_map_dispositions: Vec::new(),
4627 })
4628}
4629
4630fn linked_materialization_separator_byte_len(
4631 materialization: &LinkedEmissionArtifactV0,
4632) -> Result<usize, String> {
4633 let mut cursor = 0usize;
4634 let mut separator_byte_len = 0usize;
4635 for region in &materialization.module_regions {
4636 if region.generated_start < cursor
4637 || region.generated_start > region.generated_end
4638 || region.generated_end > materialization.output_css.len()
4639 {
4640 return Err(format!(
4641 "linked execution evidence has invalid materialized region {}..{} after {cursor}",
4642 region.generated_start, region.generated_end
4643 ));
4644 }
4645 separator_byte_len += region.generated_start - cursor;
4646 cursor = region.generated_end;
4647 }
4648 separator_byte_len += materialization.output_css.len() - cursor;
4649 Ok(separator_byte_len)
4650}
4651
4652fn bundle_execution_field_scopes() -> Vec<OmenaQueryExecutionFieldScopeV0> {
4653 use OmenaQueryExecutionEvidenceScopeV0::{Bundle, Entry};
4654
4655 vec![
4656 execution_field_scope("schemaVersion", Entry, "retained entry execution schema"),
4657 execution_field_scope("product", Entry, "retained entry execution product"),
4658 execution_field_scope("inputByteLen", Entry, "retained entry source byte length"),
4659 execution_field_scope(
4660 "outputByteLen",
4661 Bundle,
4662 "materialized linked bundle output byte length",
4663 ),
4664 execution_field_scope(
4665 "requestedPassIds",
4666 Entry,
4667 "retained entry requested pass identifiers",
4668 ),
4669 execution_field_scope(
4670 "orderedPassIds",
4671 Entry,
4672 "retained entry ordered pass identifiers",
4673 ),
4674 execution_field_scope(
4675 "executedPassIds",
4676 Entry,
4677 "retained entry executed pass identifiers",
4678 ),
4679 execution_field_scope(
4680 "plannedOnlyPassIds",
4681 Entry,
4682 "retained entry planned-only pass identifiers",
4683 ),
4684 execution_field_scope("mutationCount", Entry, "retained entry mutation count"),
4685 execution_field_scope(
4686 "provenancePreserved",
4687 Entry,
4688 "retained entry provenance status",
4689 ),
4690 execution_field_scope("outputCss", Bundle, "materialized linked bundle CSS"),
4691 execution_field_scope(
4692 "cssModuleEvaluation",
4693 Entry,
4694 "retained entry CSS module evaluation",
4695 ),
4696 execution_field_scope(
4697 "cssImportInlines",
4698 Entry,
4699 "retained entry import-inline outcomes",
4700 ),
4701 execution_field_scope(
4702 "cssModuleComposesExports",
4703 Entry,
4704 "retained entry composes exports",
4705 ),
4706 execution_field_scope(
4707 "designTokenRoutes",
4708 Entry,
4709 "retained entry design-token routes",
4710 ),
4711 execution_field_scope(
4712 "semanticRemovals",
4713 Entry,
4714 "retained entry semantic removals",
4715 ),
4716 execution_field_scope(
4717 "moduleQualifiedShake",
4718 Entry,
4719 "retained entry module-qualified shake summary",
4720 ),
4721 execution_field_scope(
4722 "cascadeProofObligations",
4723 Entry,
4724 "retained entry cascade proof obligations",
4725 ),
4726 execution_field_scope(
4727 "winnerEqualityObligations",
4728 Entry,
4729 "retained entry winner-equality obligations",
4730 ),
4731 execution_field_scope(
4732 "provenanceDerivationForest",
4733 Entry,
4734 "retained entry provenance derivation forest",
4735 ),
4736 execution_field_scope(
4737 "structuralIrTransactionTelemetry",
4738 Entry,
4739 "retained entry structural transaction telemetry",
4740 ),
4741 execution_field_scope(
4742 "semanticPreservationTelemetry",
4743 Entry,
4744 "retained entry semantic preservation telemetry",
4745 ),
4746 execution_field_scope(
4747 "dischargeLedgerTelemetry",
4748 Entry,
4749 "retained entry discharge ledger telemetry",
4750 ),
4751 execution_field_scope(
4752 "strictPolicy",
4753 Entry,
4754 "retained entry strict-policy summary",
4755 ),
4756 execution_field_scope(
4757 "closedWorldAdmission",
4758 Entry,
4759 "retained entry closed-world admission summary",
4760 ),
4761 execution_field_scope("decisions", Entry, "retained entry transform decisions"),
4762 execution_field_scope("outcomes", Entry, "retained entry pass outcomes"),
4763 execution_field_scope("passPlan", Entry, "retained entry transform pass plan"),
4764 ]
4765}
4766
4767const fn execution_field_scope(
4768 field_name: &'static str,
4769 scope: OmenaQueryExecutionEvidenceScopeV0,
4770 derivation: &'static str,
4771) -> OmenaQueryExecutionFieldScopeV0 {
4772 OmenaQueryExecutionFieldScopeV0 {
4773 field_name,
4774 scope,
4775 derivation,
4776 }
4777}
4778
4779pub(crate) fn build_closed_world_bundle_for_single_style_source_context(
4780 style_path: &str,
4781 style_source: &str,
4782 requested_pass_ids: &[String],
4783 context: &TransformExecutionContextV0,
4784) -> Option<ClosedWorldBundleV0> {
4785 build_closed_world_outcome_for_single_style_source_context(
4786 style_path,
4787 style_source,
4788 requested_pass_ids,
4789 context,
4790 )
4791 .bundle()
4792 .cloned()
4793}
4794
4795pub fn summarize_omena_query_closed_world_outcome_for_style_source(
4796 style_path: &str,
4797 style_source: &str,
4798 requested_pass_ids: &[String],
4799 context: &TransformExecutionContextV0,
4800) -> OmenaQueryClosedWorldOutcomeV0 {
4801 let context = merge_single_source_transform_context(style_path, style_source, context);
4802 build_closed_world_outcome_for_single_style_source_context(
4803 style_path,
4804 style_source,
4805 requested_pass_ids,
4806 &context,
4807 )
4808}
4809
4810#[allow(deprecated)]
4811fn build_closed_world_outcome_for_single_style_source_context(
4812 style_path: &str,
4813 style_source: &str,
4814 requested_pass_ids: &[String],
4815 context: &TransformExecutionContextV0,
4816) -> OmenaQueryClosedWorldOutcomeV0 {
4817 let source = OmenaQueryStyleSourceInputV0 {
4818 style_path: style_path.to_string(),
4819 style_source: style_source.to_string(),
4820 };
4821 let sources = std::slice::from_ref(&source);
4822 let resolution_inputs = OmenaQueryStyleResolutionInputsV0::default();
4823 let reachability_input =
4824 transform_bundle_semantic_reachability_input_from_context(style_path, context);
4825 let reachability_inputs = std::slice::from_ref(&reachability_input);
4826 let prepared = prepare_transform_bundle_linker_projection(
4827 &[style_path],
4828 sources,
4829 reachability_inputs,
4830 TransformResolutionContext::from_resolution_inputs(&resolution_inputs),
4831 );
4832 let module_metadata =
4833 style_sources_to_closed_world_metadata(&prepared.projection, context, &[], false);
4834 if !reachability_input.analysis.is_analyzed() {
4835 if requested_pass_ids_include_tree_shake(requested_pass_ids) {
4836 return OmenaQueryClosedWorldOutcomeV0::Open {
4837 blockers: vec![OmenaQueryClosedWorldBlockerV0::ClosedWorldPassUnavailable {
4838 requested_pass_ids: requested_pass_ids.to_vec(),
4839 }],
4840 };
4841 }
4842 return closed_world_outcome_from_link_result(
4843 link_omena_transform_bundle_projection_with_resolved_dependencies_and_options(
4844 &[style_path],
4845 &prepared.projection,
4846 prepared.resolved_dependencies.as_slice(),
4847 &module_metadata,
4848 TransformBundleLinkOptionsV0::default(),
4849 ),
4850 requested_pass_ids,
4851 );
4852 }
4853
4854 closed_world_outcome_from_link_result(
4855 link_omena_transform_bundle_projection_with_resolved_dependencies_and_options(
4856 &[style_path],
4857 &prepared.projection,
4858 prepared.resolved_dependencies.as_slice(),
4859 &module_metadata,
4860 TransformBundleLinkOptionsV0::default(),
4861 ),
4862 requested_pass_ids,
4863 )
4864}
4865
4866fn style_sources_to_transform_bundle_modules(
4867 style_sources: &[OmenaQueryStyleSourceInputV0],
4868) -> Vec<TransformBundleParsedModuleInputV0> {
4869 style_sources
4870 .iter()
4871 .map(|source| {
4872 let dialect = omena_parser_dialect_for_style_path(source.style_path.as_str());
4873 let parsed =
4874 parse_omena_query_omena_parser_style_source(source.style_source.as_str(), dialect);
4875 TransformBundleParsedModuleInputV0::new(
4876 source.style_path.as_str(),
4877 dialect,
4878 omena_parser::facts_from_cst(source.style_source.as_str(), &parsed),
4879 )
4880 .with_emission_selectors(
4881 omena_parser::collect_emission_selector_facts_from_cst(
4882 source.style_source.as_str(),
4883 &parsed,
4884 ),
4885 )
4886 })
4887 .collect()
4888}
4889
4890fn style_sources_to_closed_world_metadata(
4891 projection: &TransformBundleLinkerProjectionV0,
4892 context: &TransformExecutionContextV0,
4893 external_sifs: &[OmenaQueryExternalSifInputV0],
4894 source_set_closed: bool,
4895) -> Vec<ClosedWorldModuleMetadataV0> {
4896 projection
4897 .inputs()
4898 .iter()
4899 .map(|input| {
4900 let source_precision = if projection
4901 .module_reachability_analysis(&input.instance)
4902 .is_analyzed()
4903 {
4904 ClosedWorldSourcePrecisionSummaryV0 {
4905 conservative_source_count: 1,
4906 ..ClosedWorldSourcePrecisionSummaryV0::default()
4907 }
4908 } else {
4909 closed_world_source_precision_summary(context)
4910 };
4911 let mut metadata = ClosedWorldModuleMetadataV0::new(input.instance.clone())
4912 .with_interface_hash(linker_input_interface_hash(
4913 input.source_path.as_str(),
4914 input.class_names.as_slice(),
4915 input.keyframe_names.as_slice(),
4916 input.value_names.as_slice(),
4917 input.custom_property_names.as_slice(),
4918 ))
4919 .with_source_precision(source_precision)
4920 .with_composes_scan_state(if source_set_closed {
4921 ClosedWorldComposesScanStateV0::ScannedClosed
4922 } else {
4923 ClosedWorldComposesScanStateV0::SourceSetOpen
4924 });
4925 if let Some(interface_hash) = external_sifs.iter().find_map(|external_sif| {
4926 sif_matches_style_path(external_sif, input.source_path.as_str()).then(|| {
4927 external_sif
4928 .sif
4929 .fingerprints
4930 .interface_hash
4931 .as_str()
4932 .to_string()
4933 })
4934 }) {
4935 metadata = metadata.with_interface_hash(interface_hash);
4936 }
4937 metadata
4938 })
4939 .collect()
4940}
4941
4942fn linker_input_interface_hash(
4943 source_path: &str,
4944 class_names: &[String],
4945 keyframe_names: &[String],
4946 value_names: &[String],
4947 custom_property_names: &[AuthoredPropertyTextV0],
4948) -> String {
4949 let mut digest = 0xcbf2_9ce4_8422_2325_u64;
4950 hash_linker_interface_piece(&mut digest, source_path);
4951 for domain in [class_names, keyframe_names, value_names] {
4952 for value in domain {
4953 hash_linker_interface_piece(&mut digest, value);
4954 }
4955 digest ^= 0xff;
4956 digest = digest.wrapping_mul(0x0000_0100_0000_01b3);
4957 }
4958 for value in custom_property_names {
4959 hash_linker_interface_piece(&mut digest, value.to_custom_key().as_str());
4960 }
4961 digest ^= 0xff;
4962 digest = digest.wrapping_mul(0x0000_0100_0000_01b3);
4963 format!("local-interface-fnv1a64:{digest:016x}")
4964}
4965
4966fn hash_linker_interface_piece(digest: &mut u64, value: &str) {
4967 for byte in value.as_bytes().iter().copied().chain([0]) {
4968 *digest ^= u64::from(byte);
4969 *digest = digest.wrapping_mul(0x0000_0100_0000_01b3);
4970 }
4971}
4972
4973fn closed_world_source_precision_summary(
4974 context: &TransformExecutionContextV0,
4975) -> ClosedWorldSourcePrecisionSummaryV0 {
4976 let precision = if context.reachable_class_names.is_empty()
4977 && context.reachable_keyframe_names.is_empty()
4978 && context.reachable_value_names.is_empty()
4979 && context.reachable_custom_property_names.is_empty()
4980 {
4981 FactPrecision::Unknown
4982 } else {
4983 FactPrecision::Conservative
4984 };
4985 let mut summary = ClosedWorldSourcePrecisionSummaryV0::default();
4986 match precision {
4987 FactPrecision::Exact => summary.exact_source_count = 1,
4988 FactPrecision::Conservative => summary.conservative_source_count = 1,
4989 FactPrecision::Heuristic => summary.heuristic_source_count = 1,
4990 FactPrecision::Unknown => summary.unknown_source_count = 1,
4991 }
4992 summary
4993}
4994
4995fn closed_world_bundle_reachability_precision(
4996 context: &TransformExecutionContextV0,
4997 bundle: &ClosedWorldBundleV0,
4998) -> FactPrecision {
4999 let precision_ceiling = bundle.source_precision().and_then(|precision| {
5000 if precision.unknown_source_count > 0 {
5001 Some(FactPrecision::Unknown)
5002 } else if precision.heuristic_source_count > 0 {
5003 Some(FactPrecision::Heuristic)
5004 } else if precision.conservative_source_count > 0 {
5005 Some(FactPrecision::Conservative)
5006 } else if precision.exact_source_count > 0 {
5007 Some(FactPrecision::Exact)
5008 } else {
5009 None
5010 }
5011 });
5012 classify_transform_reachability_precision(context, true, precision_ceiling)
5013}
5014
5015fn sif_matches_style_path(external_sif: &OmenaQueryExternalSifInputV0, style_path: &str) -> bool {
5016 let style_path = normalize_omena_sif_location_spelling_v1(style_path);
5017 [
5018 external_sif.canonical_url.as_str(),
5019 external_sif.sif.canonical_url.as_str(),
5020 ]
5021 .into_iter()
5022 .map(normalize_omena_sif_location_spelling_v1)
5023 .any(|candidate| candidate == style_path)
5024}
5025
5026fn closed_world_outcome_from_link_result(
5027 result: Result<omena_query_transform_runner::LinkedStylesheetV0, TransformBundleLinkErrorV0>,
5028 requested_pass_ids: &[String],
5029) -> OmenaQueryClosedWorldOutcomeV0 {
5030 match result {
5031 Ok(linked) => OmenaQueryClosedWorldOutcomeV0::Closed {
5032 bundle: Box::new(linked.closed_world_bundle),
5033 },
5034 Err(error) => OmenaQueryClosedWorldOutcomeV0::Open {
5035 blockers: vec![closed_world_blocker_from_link_error(
5036 error,
5037 requested_pass_ids,
5038 )],
5039 },
5040 }
5041}
5042
5043fn closed_world_blocker_from_link_error(
5044 error: TransformBundleLinkErrorV0,
5045 requested_pass_ids: &[String],
5046) -> OmenaQueryClosedWorldBlockerV0 {
5047 match error {
5048 TransformBundleLinkErrorV0::MissingEntrypoint { source_path } => {
5049 OmenaQueryClosedWorldBlockerV0::MissingEntrypoint { source_path }
5050 }
5051 TransformBundleLinkErrorV0::AmbiguousModulePath { source_path } => {
5052 OmenaQueryClosedWorldBlockerV0::AmbiguousModulePath { source_path }
5053 }
5054 TransformBundleLinkErrorV0::MissingDependency {
5055 source_path,
5056 import_source,
5057 }
5058 | TransformBundleLinkErrorV0::UnresolvedDependencyEdge {
5059 source_path,
5060 import_source,
5061 ..
5062 } => OmenaQueryClosedWorldBlockerV0::MissingDependency {
5063 source_path,
5064 import_source,
5065 },
5066 TransformBundleLinkErrorV0::ClosedWorldBundle { error } => match error {
5067 ClosedWorldBundleBuildErrorV0::EmptyEntrypoints => {
5068 OmenaQueryClosedWorldBlockerV0::EmptyEntrypoints
5069 }
5070 ClosedWorldBundleBuildErrorV0::MissingEntrypoint { module } => {
5071 OmenaQueryClosedWorldBlockerV0::MissingModuleInstance { module }
5072 }
5073 ClosedWorldBundleBuildErrorV0::MissingDependency { module, dependency } => {
5074 OmenaQueryClosedWorldBlockerV0::MissingModuleDependency { module, dependency }
5075 }
5076 },
5077 TransformBundleLinkErrorV0::UnsupportedDialectEmissionCycle {
5078 dialect,
5079 class,
5080 edge_kinds,
5081 } => OmenaQueryClosedWorldBlockerV0::UnsupportedDialectEmissionCycle {
5082 dialect,
5083 class,
5084 edge_kinds,
5085 },
5086 TransformBundleLinkErrorV0::InvalidEmissionPlan { .. }
5087 | TransformBundleLinkErrorV0::UnsupportedEmissionCycle { .. } => {
5088 OmenaQueryClosedWorldBlockerV0::ClosedWorldPassUnavailable {
5089 requested_pass_ids: requested_pass_ids.to_vec(),
5090 }
5091 }
5092 }
5093}
5094
5095#[allow(deprecated)]
5096fn transform_bundle_semantic_reachability_input_from_context(
5097 style_path: &str,
5098 context: &TransformExecutionContextV0,
5099) -> TransformBundleSemanticReachabilityInputV0 {
5100 transform_bundle_semantic_reachability_input_from_context_and_attribution(
5101 style_path, context, None,
5102 )
5103}
5104
5105#[allow(deprecated)]
5106fn transform_bundle_semantic_reachability_input_from_context_and_attribution(
5107 style_path: &str,
5108 context: &TransformExecutionContextV0,
5109 attribution_report: Option<&OmenaQueryModuleReachabilityAttributionReportV0>,
5110) -> TransformBundleSemanticReachabilityInputV0 {
5111 let mut class_names = context.reachable_class_names.clone();
5112 let attribution = attribution_report.and_then(|report| report.entry_for_style_path(style_path));
5113 if let Some(attribution) = attribution {
5114 class_names.extend(attribution.class_names().iter().cloned());
5115 }
5116 class_names.sort();
5117 class_names.dedup();
5118 let has_explicit_symbols = !class_names.is_empty()
5119 || !context.reachable_keyframe_names.is_empty()
5120 || !context.reachable_value_names.is_empty()
5121 || !context.reachable_custom_property_names.is_empty();
5122 let analysis = if has_explicit_symbols || attribution.is_some_and(|entry| entry.was_attempted())
5123 {
5124 TransformBundleReachabilityAnalysisV0::Analyzed
5125 } else if attribution_report.is_none() {
5126 TransformBundleReachabilityAnalysisV0::Unanalyzed {
5127 cause: TransformBundleReachabilityUnanalyzedCauseV0::InputNotProvided,
5128 }
5129 } else if attribution.is_some() {
5130 TransformBundleReachabilityAnalysisV0::Unanalyzed {
5131 cause: TransformBundleReachabilityUnanalyzedCauseV0::AnalysisNotAttempted,
5132 }
5133 } else {
5134 TransformBundleReachabilityAnalysisV0::Unanalyzed {
5135 cause: TransformBundleReachabilityUnanalyzedCauseV0::AnalysisResultUnavailable,
5136 }
5137 };
5138 let mut input = match analysis {
5139 TransformBundleReachabilityAnalysisV0::Analyzed => {
5140 TransformBundleSemanticReachabilityInputV0::new(style_path)
5141 }
5142 TransformBundleReachabilityAnalysisV0::Unanalyzed { cause } => {
5143 TransformBundleSemanticReachabilityInputV0::unanalyzed(style_path, cause)
5144 }
5145 _ => TransformBundleSemanticReachabilityInputV0::unanalyzed(
5146 style_path,
5147 TransformBundleReachabilityUnanalyzedCauseV0::AnalysisResultUnavailable,
5148 ),
5149 };
5150 input.class_names = class_names;
5151 input.keyframe_names = context.reachable_keyframe_names.clone();
5152 input.value_names = context.reachable_value_names.clone();
5153 input.custom_property_names = context.reachable_custom_property_names.clone();
5154 input
5155}
5156
5157fn transform_pass_kind_from_id(pass_id: &str) -> Option<TransformPassKind> {
5158 all_transform_pass_kinds()
5159 .into_iter()
5160 .find(|candidate| candidate.id() == pass_id)
5161}
5162
5163#[cfg(test)]
5164mod linked_source_map_tests {
5165 use super::*;
5166
5167 #[test]
5168 fn equal_injected_tokens_activate_cross_module_retention_guard() -> Result<(), String> {
5169 let entry = omena_parser::ModuleInstanceKeyV0::unconfigured(omena_parser::ModuleIdV0::new(
5170 "src/entry.module.css",
5171 ));
5172 let dependency = omena_parser::ModuleInstanceKeyV0::unconfigured(
5173 omena_parser::ModuleIdV0::new("src/dependency.module.css"),
5174 );
5175 let sources = vec![
5176 OmenaQueryStyleSourceInputV0 {
5177 style_path: entry.module().as_str().to_string(),
5178 style_source:
5179 ".entry { composes: live from './dependency.module.css'; color: red; }"
5180 .to_string(),
5181 },
5182 OmenaQueryStyleSourceInputV0 {
5183 style_path: dependency.module().as_str().to_string(),
5184 style_source: ".live { color: blue; } .shared { color: green; }".to_string(),
5185 },
5186 ];
5187 let resolution_inputs = OmenaQueryStyleResolutionInputsV0::default();
5188 let prepared = prepare_transform_bundle_linker_projection(
5189 &[entry.module().as_str()],
5190 &sources,
5191 &[],
5192 TransformResolutionContext::from_resolution_inputs(&resolution_inputs),
5193 );
5194 let linked = link_omena_transform_bundle_projection_with_resolved_dependencies_and_options(
5195 &[entry.module().as_str()],
5196 &prepared.projection,
5197 prepared.resolved_dependencies.as_slice(),
5198 &[],
5199 TransformBundleLinkOptionsV0::default(),
5200 )
5201 .map_err(|error| format!("{error:?}"))?;
5202 let bundle = linked.closed_world_bundle;
5203 let entry_context = TransformExecutionContextV0 {
5204 class_name_rewrites: vec![TransformClassNameRewriteV0 {
5205 original_name: "entry".to_string(),
5206 rewritten_name: "_forced_shared".to_string(),
5207 }],
5208 ..TransformExecutionContextV0::default()
5209 };
5210 let dependency_context = TransformExecutionContextV0 {
5211 class_name_rewrites: vec![TransformClassNameRewriteV0 {
5212 original_name: "injected".to_string(),
5213 rewritten_name: "_forced_shared".to_string(),
5214 }],
5215 ..TransformExecutionContextV0::default()
5216 };
5217 let inputs = vec![
5218 LinkedModuleExecutionInputV0 {
5219 module_instance: &entry,
5220 ownership_module_instance: entry.clone(),
5221 style_source: ".entry { color: red; }".to_string(),
5222 context: entry_context,
5223 },
5224 LinkedModuleExecutionInputV0 {
5225 module_instance: &dependency,
5226 ownership_module_instance: dependency.clone(),
5227 style_source: ".live { color: blue; } .shared { color: green; }".to_string(),
5228 context: dependency_context,
5229 },
5230 ];
5231
5232 let retained = retained_class_names_for_live_linked_emission_tokens(&bundle, &inputs);
5233 assert_eq!(retained.get(&entry), Some(&Vec::<String>::new()));
5234 assert_eq!(
5235 retained.get(&dependency),
5236 Some(&vec!["injected".to_string()])
5237 );
5238 Ok(())
5239 }
5240
5241 #[derive(Debug)]
5242 struct DecodedSourceMapSegment {
5243 generated_line: usize,
5244 generated_column: usize,
5245 source_index: usize,
5246 original_line: usize,
5247 original_column: usize,
5248 }
5249
5250 fn decode_source_map_mappings(mappings: &str) -> Result<Vec<DecodedSourceMapSegment>, String> {
5251 let mut decoded = Vec::new();
5252 let mut previous_source_index = 0isize;
5253 let mut previous_original_line = 0isize;
5254 let mut previous_original_column = 0isize;
5255 for (generated_line, line) in mappings.split(';').enumerate() {
5256 let mut previous_generated_column = 0isize;
5257 for segment in line.split(',').filter(|segment| !segment.is_empty()) {
5258 let values = decode_source_map_vlq_values(segment)?;
5259 if values.len() < 4 {
5260 return Err(format!(
5261 "source-map segment has too few fields: {segment:?}"
5262 ));
5263 }
5264 previous_generated_column += values[0];
5265 previous_source_index += values[1];
5266 previous_original_line += values[2];
5267 previous_original_column += values[3];
5268 if previous_generated_column < 0
5269 || previous_source_index < 0
5270 || previous_original_line < 0
5271 || previous_original_column < 0
5272 {
5273 return Err(format!("source-map segment underflowed: {segment:?}"));
5274 }
5275 decoded.push(DecodedSourceMapSegment {
5276 generated_line,
5277 generated_column: previous_generated_column as usize,
5278 source_index: previous_source_index as usize,
5279 original_line: previous_original_line as usize,
5280 original_column: previous_original_column as usize,
5281 });
5282 }
5283 }
5284 Ok(decoded)
5285 }
5286
5287 fn decode_source_map_vlq_values(segment: &str) -> Result<Vec<isize>, String> {
5288 const BASE64: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5289 let mut values = Vec::new();
5290 let mut value = 0usize;
5291 let mut shift = 0usize;
5292 for character in segment.chars() {
5293 let digit = BASE64
5294 .find(character)
5295 .ok_or_else(|| format!("invalid source-map digit {character:?}"))?;
5296 value |= (digit & 31) << shift;
5297 if digit & 32 == 0 {
5298 let magnitude = (value >> 1) as isize;
5299 values.push(if value & 1 == 0 {
5300 magnitude
5301 } else {
5302 -magnitude
5303 });
5304 value = 0;
5305 shift = 0;
5306 } else {
5307 shift += 5;
5308 }
5309 }
5310 if shift != 0 {
5311 return Err("unterminated source-map VLQ value".to_string());
5312 }
5313 Ok(values)
5314 }
5315
5316 #[test]
5317 fn linked_bundle_retains_each_module_execution_before_bundle_projection() -> Result<(), String>
5318 {
5319 let style_sources = vec![
5320 OmenaQueryStyleSourceInputV0 {
5321 style_path: "src/app.module.css".to_string(),
5322 style_source:
5323 ".app { composes: token from \"./tokens.module.css\"; color: green; }\n"
5324 .to_string(),
5325 },
5326 OmenaQueryStyleSourceInputV0 {
5327 style_path: "src/tokens.module.css".to_string(),
5328 style_source:
5329 "@import \"./base.css\";\n.token { color: blue; }\n.dead { color: black; }\n"
5330 .to_string(),
5331 },
5332 OmenaQueryStyleSourceInputV0 {
5333 style_path: "src/base.css".to_string(),
5334 style_source: ".base { color: red; }\n".to_string(),
5335 },
5336 ];
5337 let pass_ids = vec![
5338 "import-inline".to_string(),
5339 "tree-shake-class".to_string(),
5340 "print-css".to_string(),
5341 ];
5342 let context = OmenaQueryTransformExecutionContextV0 {
5343 reachable_class_names: vec!["app".to_string(), "base".to_string(), "token".to_string()],
5344 ..OmenaQueryTransformExecutionContextV0::default()
5345 };
5346 let resolution_inputs = OmenaQueryStyleResolutionInputsV0::default();
5347 let link_options = TransformBundleLinkOptionsV0::default()
5348 .with_emission_ordering_policy(EmissionOrderingPolicyV0::ImportOrderPreserving);
5349 let admission = link_closed_world_stylesheet_for_style_sources(
5350 ClosedWorldStylesheetRequestV0 {
5351 target_style_path: "src/app.module.css",
5352 style_sources: &style_sources,
5353 requested_pass_ids: &pass_ids,
5354 context: &context,
5355 reachability_context: &context,
5356 attribution_report: None,
5357 resolution_inputs: &resolution_inputs,
5358 external_sifs: &[],
5359 source_set_closed: true,
5360 },
5361 link_options,
5362 );
5363 let linked = admission
5364 .into_requested_policy_result()
5365 .map_err(|error| format!("retention fixture should link: {error:?}"))?;
5366 let style_fact_entries = style_sources
5367 .iter()
5368 .map(|source| {
5369 collect_omena_query_style_fact_entry(
5370 source.style_path.as_str(),
5371 source.style_source.as_str(),
5372 )
5373 })
5374 .collect::<Vec<_>>();
5375 let execution = execute_linked_bundle_modules_with_ownership_reference(
5376 &linked,
5377 "src/app.module.css",
5378 &style_sources,
5379 &style_fact_entries,
5380 &pass_ids,
5381 &context,
5382 &[],
5383 None,
5384 &resolution_inputs,
5385 &[],
5386 &OmenaQueryConsumerBuildOptionsV0 {
5387 bundle_emission_path: OmenaQueryBundleEmissionPathV0::LinkedOrder,
5388 ..OmenaQueryConsumerBuildOptionsV0::default()
5389 },
5390 )?;
5391
5392 assert_eq!(
5393 execution.module_executions.len(),
5394 linked.linked_stylesheet.module_instances.len()
5395 );
5396 let retained_keys = execution
5397 .module_executions
5398 .iter()
5399 .map(|module| module.module_instance.clone())
5400 .collect::<BTreeSet<_>>();
5401 assert_eq!(retained_keys.len(), execution.module_executions.len());
5402
5403 let target_instance = linked
5404 .linked_stylesheet
5405 .entrypoints
5406 .first()
5407 .ok_or_else(|| "retention fixture should have an entrypoint".to_string())?;
5408 let retained_entry = execution
5409 .module_executions
5410 .iter()
5411 .find(|module| &module.module_instance == target_instance)
5412 .ok_or_else(|| "entry execution should be retained".to_string())?;
5413 let mutating_dependency = execution
5414 .module_executions
5415 .iter()
5416 .find(|module| module.module_instance.module().as_str() == "src/tokens.module.css")
5417 .ok_or_else(|| "mutating dependency execution should be retained".to_string())?;
5418 assert_eq!(
5421 (
5422 retained_entry.execution.mutation_count,
5423 retained_entry.execution.semantic_removals.len(),
5424 retained_entry
5425 .execution
5426 .executed_pass_ids
5427 .contains(&"import-inline"),
5428 mutating_dependency.execution.mutation_count,
5429 mutating_dependency.execution.semantic_removals.len(),
5430 mutating_dependency
5431 .execution
5432 .executed_pass_ids
5433 .contains(&"import-inline"),
5434 execution.execution.mutation_count,
5435 ),
5436 (0, 0, false, 2, 1, true, 0)
5437 );
5438 assert_eq!(
5441 execution.materialization.output_css,
5442 ".base { color: red; }\n\n.token { color: blue; }\n\n.app { composes: token from \"./tokens.module.css\"; color: green; }\n"
5443 );
5444 let scope_evidence = summarize_linked_bundle_execution_scope(&execution)?;
5445 assert_eq!(
5448 (
5449 scope_evidence.bundle_execution.aggregate_mutation_count,
5450 scope_evidence
5451 .bundle_execution
5452 .aggregate_executed_pass_ids
5453 .as_slice(),
5454 scope_evidence
5455 .bundle_execution
5456 .aggregate_semantic_removal_count,
5457 scope_evidence
5458 .bundle_execution
5459 .aggregate_closed_world_refusal_count,
5460 ),
5461 (
5462 2,
5463 ["tree-shake-class", "print-css", "import-inline"].as_slice(),
5464 1,
5465 0,
5466 )
5467 );
5468 assert_eq!(
5471 (
5472 scope_evidence.bundle_execution.module_executions.len(),
5473 scope_evidence
5474 .bundle_execution
5475 .emission_execution
5476 .module_regions
5477 .len(),
5478 scope_evidence
5479 .bundle_execution
5480 .emission_execution
5481 .emitted_module_count,
5482 ),
5483 (3, 3, 3)
5484 );
5485 assert_eq!(scope_evidence.field_scopes.len(), 28);
5486 assert_eq!(scope_evidence.module_executions.len(), 3);
5487 assert_eq!(
5488 scope_evidence.bundle_composite.module_count,
5489 scope_evidence.module_executions.len()
5490 );
5491 assert_eq!(
5492 scope_evidence
5493 .module_executions
5494 .iter()
5495 .map(|module| module.input_byte_len)
5496 .sum::<usize>(),
5497 scope_evidence.bundle_composite.summed_module_input_byte_len
5498 );
5499 assert_eq!(
5500 scope_evidence
5501 .module_executions
5502 .iter()
5503 .map(|module| module.output_byte_len)
5504 .sum::<usize>(),
5505 scope_evidence
5506 .bundle_composite
5507 .summed_module_output_byte_len
5508 );
5509 assert_eq!(
5510 scope_evidence
5511 .bundle_composite
5512 .summed_module_output_byte_len
5513 + scope_evidence
5514 .bundle_composite
5515 .inter_module_separator_byte_len,
5516 scope_evidence.bundle_composite.materialized_output_byte_len
5517 );
5518
5519 let retained_json =
5520 serde_json::to_value(&retained_entry.execution).map_err(|error| error.to_string())?;
5521 let projected_json =
5522 serde_json::to_value(&execution.execution).map_err(|error| error.to_string())?;
5523 let conditionally_serialized_fields = scope_evidence
5524 .field_scopes
5525 .iter()
5526 .filter(|field| {
5527 retained_json.get(field.field_name).is_none()
5528 && projected_json.get(field.field_name).is_none()
5529 })
5530 .map(|field| field.field_name)
5531 .collect::<BTreeSet<_>>();
5532 for field in &scope_evidence.field_scopes {
5533 let projected_value = projected_json.get(field.field_name);
5534 match field.scope {
5535 OmenaQueryExecutionEvidenceScopeV0::Entry => {
5536 let retained_value = retained_json.get(field.field_name);
5537 if !conditionally_serialized_fields.contains(field.field_name) {
5538 assert!(
5541 projected_value.is_some() && retained_value.is_some(),
5542 "required entry-scoped field {} must be present on both executions",
5543 field.field_name
5544 );
5545 }
5546 assert_eq!(
5547 projected_value.is_some(),
5548 retained_value.is_some(),
5549 "entry-scoped field {} must have symmetric presence",
5550 field.field_name
5551 );
5552 assert_eq!(
5553 projected_value, retained_value,
5554 "entry-scoped field {}",
5555 field.field_name
5556 );
5557 }
5558 OmenaQueryExecutionEvidenceScopeV0::Bundle => match field.field_name {
5559 "outputByteLen" => assert_eq!(
5560 projected_value,
5561 Some(&serde_json::json!(
5562 execution.materialization.output_css.len()
5563 ))
5564 ),
5565 "outputCss" => assert_eq!(
5566 projected_value,
5567 Some(&serde_json::json!(execution.materialization.output_css))
5568 ),
5569 field_name => {
5570 return Err(format!("field {field_name} has no bundle-scope derivation"));
5571 }
5572 },
5573 }
5574 }
5575
5576 let mut expected_projected_json = retained_json;
5577 let expected_object = expected_projected_json
5578 .as_object_mut()
5579 .ok_or_else(|| "retained execution should serialize as an object".to_string())?;
5580 expected_object.insert(
5581 "outputByteLen".to_string(),
5582 serde_json::json!(execution.materialization.output_css.len()),
5583 );
5584 expected_object.insert(
5585 "outputCss".to_string(),
5586 serde_json::json!(execution.materialization.output_css),
5587 );
5588 assert_eq!(expected_projected_json, projected_json);
5589
5590 let retained_bundle_module = scope_evidence
5591 .bundle_execution
5592 .module_executions
5593 .first()
5594 .ok_or_else(|| "bundle execution should retain a module sample".to_string())?;
5595 let serialized_bundle_module = serde_json::to_value(retained_bundle_module)
5596 .map_err(|error| format!("bundle module execution should serialize: {error}"))?;
5597 let serialized_object = serialized_bundle_module
5598 .as_object()
5599 .ok_or_else(|| "bundle module execution should serialize as an object".to_string())?;
5600 let mut serialized_keys = serialized_object.keys().cloned().collect::<Vec<_>>();
5601 serialized_keys.sort();
5602 let serialized_wire_types = serialized_keys
5603 .iter()
5604 .map(|key| {
5605 let wire_type = match serialized_object.get(key) {
5606 Some(serde_json::Value::Object(_)) => "object",
5607 Some(value) => {
5608 return Err(format!(
5609 "bundle module execution field {key} has unexpected value {value:?}"
5610 ));
5611 }
5612 None => return Err(format!("bundle module execution is missing {key}")),
5613 };
5614 Ok((key.clone(), wire_type))
5615 })
5616 .collect::<Result<BTreeMap<_, _>, String>>()?;
5617 let actual_wire_key_sample = serde_json::json!({
5618 "interfaceName": "OmenaBundleModuleExecutionV0",
5619 "keys": serialized_keys,
5620 "product": "omena-query.bundle-execution-wire-key-sample",
5621 "sampleName": "product-run",
5622 "schemaVersion": "0",
5623 "wireTypes": serialized_wire_types,
5624 });
5625 let expected_wire_key_sample: serde_json::Value = serde_json::from_str(include_str!(
5626 "../../tests/fixtures/bundle-module-execution-wire-keys.json"
5627 ))
5628 .map_err(|error| error.to_string())?;
5629 assert_eq!(actual_wire_key_sample, expected_wire_key_sample);
5632 Ok(())
5633 }
5634
5635 #[test]
5636 fn linked_bundle_retains_module_admission_refusals_before_bundle_projection()
5637 -> Result<(), String> {
5638 let style_sources = vec![
5639 OmenaQueryStyleSourceInputV0 {
5640 style_path: "src/app.module.css".to_string(),
5641 style_source:
5642 ".app { composes: token from \"./tokens.module.css\"; color: green; }\n"
5643 .to_string(),
5644 },
5645 OmenaQueryStyleSourceInputV0 {
5646 style_path: "src/tokens.module.css".to_string(),
5647 style_source:
5648 "@import \"./base.css\";\n.token { color: blue; }\n.dead { color: black; }\n"
5649 .to_string(),
5650 },
5651 OmenaQueryStyleSourceInputV0 {
5652 style_path: "src/base.css".to_string(),
5653 style_source: ".base { color: red; }\n".to_string(),
5654 },
5655 ];
5656 let pass_ids = vec![
5657 "import-inline".to_string(),
5658 "tree-shake-class".to_string(),
5659 "print-css".to_string(),
5660 ];
5661 let context = OmenaQueryTransformExecutionContextV0::default();
5662 let resolution_inputs = OmenaQueryStyleResolutionInputsV0::default();
5663 let link_options = TransformBundleLinkOptionsV0::default()
5664 .with_emission_ordering_policy(EmissionOrderingPolicyV0::ImportOrderPreserving);
5665 let admission = link_closed_world_stylesheet_for_style_sources(
5666 ClosedWorldStylesheetRequestV0 {
5667 target_style_path: "src/app.module.css",
5668 style_sources: &style_sources,
5669 requested_pass_ids: &pass_ids,
5670 context: &context,
5671 reachability_context: &context,
5672 attribution_report: None,
5673 resolution_inputs: &resolution_inputs,
5674 external_sifs: &[],
5675 source_set_closed: true,
5676 },
5677 link_options,
5678 );
5679 let linked = admission
5680 .into_requested_policy_result()
5681 .map_err(|error| format!("refusal fixture should link: {error:?}"))?;
5682 let style_fact_entries = style_sources
5683 .iter()
5684 .map(|source| {
5685 collect_omena_query_style_fact_entry(
5686 source.style_path.as_str(),
5687 source.style_source.as_str(),
5688 )
5689 })
5690 .collect::<Vec<_>>();
5691 let execution = execute_linked_bundle_modules_with_ownership_reference(
5692 &linked,
5693 "src/app.module.css",
5694 &style_sources,
5695 &style_fact_entries,
5696 &pass_ids,
5697 &context,
5698 &[],
5699 None,
5700 &resolution_inputs,
5701 &[],
5702 &OmenaQueryConsumerBuildOptionsV0 {
5703 bundle_emission_path: OmenaQueryBundleEmissionPathV0::LinkedOrder,
5704 ..OmenaQueryConsumerBuildOptionsV0::default()
5705 },
5706 )?;
5707 let entry = execution
5708 .module_executions
5709 .iter()
5710 .find(|module| module.module_instance == execution.entry_module_instance)
5711 .ok_or_else(|| "refusal fixture should retain the entry execution".to_string())?;
5712 let scope_evidence = summarize_linked_bundle_execution_scope(&execution)?;
5713
5714 assert_eq!(
5717 (
5718 entry.execution.closed_world_admission.refused_count,
5719 execution.execution.closed_world_admission.refused_count,
5720 scope_evidence
5721 .bundle_execution
5722 .aggregate_closed_world_refusal_count,
5723 ),
5724 (1, 1, 3)
5725 );
5726 Ok(())
5727 }
5728
5729 #[test]
5730 fn bundle_execution_scope_closes_materializer_regions_and_separators() -> Result<(), String> {
5731 let style_sources = vec![
5732 OmenaQueryStyleSourceInputV0 {
5733 style_path: "src/app.css".to_string(),
5734 style_source: "@import \"./tokens.css\";\n.app { color: green; }\n".to_string(),
5735 },
5736 OmenaQueryStyleSourceInputV0 {
5737 style_path: "src/tokens.css".to_string(),
5738 style_source: ".token { color: blue; }\n".to_string(),
5739 },
5740 ];
5741 let pass_ids = vec!["import-inline".to_string(), "print-css".to_string()];
5742 let context = OmenaQueryTransformExecutionContextV0::default();
5743 let resolution_inputs = OmenaQueryStyleResolutionInputsV0::default();
5744 let admission = link_closed_world_stylesheet_for_style_sources(
5745 ClosedWorldStylesheetRequestV0 {
5746 target_style_path: "src/app.css",
5747 style_sources: &style_sources,
5748 requested_pass_ids: &pass_ids,
5749 context: &context,
5750 reachability_context: &context,
5751 attribution_report: None,
5752 resolution_inputs: &resolution_inputs,
5753 external_sifs: &[],
5754 source_set_closed: true,
5755 },
5756 TransformBundleLinkOptionsV0::default()
5757 .with_emission_ordering_policy(EmissionOrderingPolicyV0::ImportOrderPreserving),
5758 );
5759 let linked = admission
5760 .into_requested_policy_result()
5761 .map_err(|error| format!("missing-region fixture should link: {error:?}"))?;
5762 let style_fact_entries = style_sources
5763 .iter()
5764 .map(|source| {
5765 collect_omena_query_style_fact_entry(
5766 source.style_path.as_str(),
5767 source.style_source.as_str(),
5768 )
5769 })
5770 .collect::<Vec<_>>();
5771 let mut execution = execute_linked_bundle_modules_with_ownership_reference(
5772 &linked,
5773 "src/app.css",
5774 &style_sources,
5775 &style_fact_entries,
5776 &pass_ids,
5777 &context,
5778 &[],
5779 None,
5780 &resolution_inputs,
5781 &[],
5782 &OmenaQueryConsumerBuildOptionsV0 {
5783 bundle_emission_path: OmenaQueryBundleEmissionPathV0::LinkedOrder,
5784 ..OmenaQueryConsumerBuildOptionsV0::default()
5785 },
5786 )?;
5787 let baseline_scope = summarize_linked_bundle_execution_scope(&execution)?;
5788 let baseline_module_output_byte_lens = baseline_scope
5789 .bundle_execution
5790 .module_executions
5791 .iter()
5792 .map(|module| module.execution.output_byte_len)
5793 .collect::<Vec<_>>();
5794 let insertion_offset = execution
5795 .materialization
5796 .module_regions
5797 .first()
5798 .ok_or_else(|| "separator fixture should have a first module region".to_string())?
5799 .generated_end;
5800 let baseline_second_region_start = execution
5801 .materialization
5802 .module_regions
5803 .get(1)
5804 .ok_or_else(|| "separator fixture should have a second module region".to_string())?
5805 .generated_start;
5806 let mut separator_execution = execution.clone();
5807 separator_execution
5808 .materialization
5809 .output_css
5810 .insert(insertion_offset, ' ');
5811 for region in separator_execution
5812 .materialization
5813 .module_regions
5814 .iter_mut()
5815 .skip(1)
5816 {
5817 region.generated_start += 1;
5818 region.generated_end += 1;
5819 }
5820 for region in &mut separator_execution.materialization.order_entry_regions {
5821 if region.generated_start >= insertion_offset {
5822 region.generated_start += 1;
5823 region.generated_end += 1;
5824 }
5825 }
5826 let separator_scope = summarize_linked_bundle_execution_scope(&separator_execution)?;
5827 let separator_module_output_byte_lens = separator_scope
5828 .bundle_execution
5829 .module_executions
5830 .iter()
5831 .map(|module| module.execution.output_byte_len)
5832 .collect::<Vec<_>>();
5833 assert_eq!(
5837 (
5838 separator_scope
5839 .bundle_composite
5840 .inter_module_separator_byte_len,
5841 separator_scope
5842 .bundle_composite
5843 .materialized_output_byte_len,
5844 separator_module_output_byte_lens,
5845 separator_scope
5846 .bundle_execution
5847 .emission_execution
5848 .module_regions[1]
5849 .generated_start,
5850 ),
5851 (
5852 baseline_scope
5853 .bundle_composite
5854 .inter_module_separator_byte_len
5855 + 1,
5856 baseline_scope.bundle_composite.materialized_output_byte_len + 1,
5857 baseline_module_output_byte_lens,
5858 baseline_second_region_start + 1,
5859 )
5860 );
5861 execution.materialization.module_regions.pop();
5862
5863 let error = match summarize_linked_bundle_execution_scope(&execution) {
5864 Err(error) => error,
5865 Ok(_) => {
5866 return Err("a retained execution without a region must be rejected".to_string());
5867 }
5868 };
5869 assert!(
5872 error.contains("has no materialized region") || error.contains("cardinality mismatch"),
5873 "unexpected missing-region error: {error}"
5874 );
5875 Ok(())
5876 }
5877
5878 #[test]
5879 fn bundle_execution_scope_wire_matches_typescript_fixture() -> Result<(), String> {
5880 let module_instance = omena_parser::ModuleInstanceKeyV0::unconfigured(
5881 omena_parser::ModuleIdV0::new("src/app.css"),
5882 );
5883 let module_source = ".appss { color: red; }\n";
5884 let execution = execute_omena_query_transform_passes_from_source(
5885 "src/app.css",
5886 module_source,
5887 &["whitespace-strip".to_string()],
5888 )
5889 .execution;
5890 assert_eq!(execution.input_byte_len, 23);
5891 assert_eq!(execution.output_byte_len, 17);
5892 let evidence = OmenaQueryBundleExecutionScopeEvidenceV0 {
5893 schema_version: "0",
5894 product: "omena-query.bundle-execution-scope",
5895 entry_module_instance: module_instance.clone(),
5896 field_scopes: vec![
5897 OmenaQueryExecutionFieldScopeV0 {
5898 field_name: "outcomes",
5899 scope: OmenaQueryExecutionEvidenceScopeV0::Entry,
5900 derivation: "retained entry outcomes",
5901 },
5902 OmenaQueryExecutionFieldScopeV0 {
5903 field_name: "outputCss",
5904 scope: OmenaQueryExecutionEvidenceScopeV0::Bundle,
5905 derivation: "materialized bundle css",
5906 },
5907 ],
5908 module_executions: vec![OmenaQueryBundleModuleExecutionByteFactsV0 {
5909 module_instance: module_instance.clone(),
5910 input_byte_len: execution.input_byte_len,
5911 output_byte_len: execution.output_byte_len,
5912 generated_start: 2,
5913 generated_end: 19,
5914 }],
5915 bundle_composite: OmenaQueryBundleCompositeExecutionByteFactsV0 {
5916 module_count: 1,
5917 summed_module_input_byte_len: execution.input_byte_len,
5918 summed_module_output_byte_len: execution.output_byte_len,
5919 inter_module_separator_byte_len: 2,
5920 materialized_output_byte_len: 19,
5921 },
5922 bundle_execution: BundleExecutionSummaryV0 {
5923 schema_version: "0",
5924 product: "omena-query.bundle-execution",
5925 entry_module_instance: module_instance.clone(),
5926 module_executions: vec![BundleModuleExecutionV0 {
5927 module_instance: module_instance.clone(),
5928 execution: execution.clone(),
5929 }],
5930 emission_execution: BundleEmissionExecutionV0 {
5931 module_regions: vec![LinkedEmissionModuleRegionV0 {
5932 module_instance: module_instance.clone(),
5933 first_global_order_index: Some(0),
5934 generated_start: 0,
5935 generated_end: execution.output_byte_len,
5936 }],
5937 order_entry_regions: vec![LinkedEmissionOrderEntryRegionV0 {
5938 global_order_index: 0,
5939 module_instance: module_instance.clone(),
5940 generated_start: 0,
5941 generated_end: execution.output_byte_len,
5942 }],
5943 emitted_module_count: 1,
5944 global_order_entry_count: 1,
5945 },
5946 aggregate_mutation_count: execution.mutation_count,
5947 aggregate_executed_pass_ids: execution.executed_pass_ids.clone(),
5948 aggregate_semantic_removal_count: execution.semantic_removals.len(),
5949 aggregate_closed_world_refusal_count: execution
5950 .closed_world_admission
5951 .refused_count,
5952 },
5953 source_map_dispositions: vec![
5954 OmenaQueryLinkedSourceMapDispositionV0 {
5955 module_instance: module_instance.clone(),
5956 granularity: OmenaQueryLinkedSourceMapGranularityV0::CstAnchors,
5957 fallback_reason: None,
5958 segment_count: 3,
5959 },
5960 OmenaQueryLinkedSourceMapDispositionV0 {
5961 module_instance,
5962 granularity: OmenaQueryLinkedSourceMapGranularityV0::WholeModuleFallback,
5963 fallback_reason: Some(LINKED_FALLBACK_SOURCE_START_REASON),
5964 segment_count: 1,
5965 },
5966 ],
5967 };
5968 let actual = serde_json::to_value(evidence).map_err(|error| error.to_string())?;
5969 let expected_fixture =
5970 include_str!("../../tests/fixtures/bundle-execution-scope-wire.json");
5971 let expected: serde_json::Value =
5972 serde_json::from_str(expected_fixture).map_err(|error| error.to_string())?;
5973 assert_eq!(actual, expected);
5974 Ok(())
5975 }
5976
5977 #[test]
5978 fn linked_bundle_source_map_uses_materialized_module_offsets() -> Result<(), String> {
5979 let style_sources = vec![
5980 OmenaQueryStyleSourceInputV0 {
5981 style_path: "src/app.css".to_string(),
5982 style_source: "@import \"./tokens.css\";\n@import \"./width.css\";\n.linked-map-app-a { color: red; }\n.linked-map-app-b { color: green; }"
5983 .to_string(),
5984 },
5985 OmenaQueryStyleSourceInputV0 {
5986 style_path: "src/tokens.css".to_string(),
5987 style_source: ".linked-map-token-a { color: blue; }\n.linked-map-token-b { color: cyan; }\n.linked-map-token-c { color: navy; }"
5988 .to_string(),
5989 },
5990 OmenaQueryStyleSourceInputV0 {
5991 style_path: "src/width.css".to_string(),
5992 style_source: ".componentAlphaLongerState, .componentBetaLongerState, .componentGammaLongerState,\n.componentDeltaLongerState, .componentEpsilonLongerState {\n color: red;\n}\n"
5993 .to_string(),
5994 },
5995 ];
5996 let modules = style_sources
5997 .iter()
5998 .map(|source| {
5999 TransformBundleModuleInputV0::new(
6000 source.style_path.clone(),
6001 source.style_source.clone(),
6002 omena_parser::StyleDialect::Css,
6003 )
6004 })
6005 .collect::<Vec<_>>();
6006 let linked = link_omena_transform_bundle_modules(&["src/app.css"], &modules)
6007 .map_err(|error| format!("source-map fixture should link: {error:?}"))?;
6008 let transformed = linked
6009 .module_instances
6010 .iter()
6011 .map(|module_instance| {
6012 let source = style_sources
6013 .iter()
6014 .find(|source| source.style_path == module_instance.module().as_str())
6015 .ok_or_else(|| {
6016 format!(
6017 "source-map fixture has no source for {:?}",
6018 module_instance.module()
6019 )
6020 })?;
6021 Ok(TransformBundleTransformedModuleV0::new(
6022 module_instance.clone(),
6023 source.style_source.clone(),
6024 ))
6025 })
6026 .collect::<Result<Vec<_>, String>>()?;
6027 let module_executions = linked
6028 .module_instances
6029 .iter()
6030 .map(|module_instance| {
6031 let source = style_sources
6032 .iter()
6033 .find(|source| source.style_path == module_instance.module().as_str())
6034 .ok_or_else(|| {
6035 format!(
6036 "source-map fixture has no execution source for {:?}",
6037 module_instance.module()
6038 )
6039 })?;
6040 let summary = execute_omena_query_consumer_build_style_source_with_context(
6041 source.style_path.as_str(),
6042 source.style_source.as_str(),
6043 &["print-css".to_string()],
6044 &TransformExecutionContextV0::default(),
6045 );
6046 Ok(LinkedModuleExecutionV0 {
6047 module_instance: module_instance.clone(),
6048 execution: summary.execution,
6049 class_name_rewrites: Vec::new(),
6050 })
6051 })
6052 .collect::<Result<Vec<_>, String>>()?;
6053 let materialization =
6054 materialize_omena_transform_bundle_linked_stylesheet(&linked, &transformed)
6055 .map_err(|error| format!("source-map fixture should materialize: {error:?}"))?;
6056 let (segments, dispositions) = linked_bundle_source_map_segments(
6057 &style_sources,
6058 &materialization.output_css,
6059 &materialization,
6060 &module_executions,
6061 )?;
6062 let cst_anchor_count = dispositions
6063 .iter()
6064 .filter(|disposition| {
6065 disposition.granularity == OmenaQueryLinkedSourceMapGranularityV0::CstAnchors
6066 })
6067 .count();
6068 let pretty_render_equality = module_executions
6069 .iter()
6070 .filter_map(|module| {
6071 let source_path = module.module_instance.module().as_str();
6072 let source = style_sources
6073 .iter()
6074 .find(|source| source.style_path == source_path)?;
6075 (source.style_source == module.execution.output_css).then(|| {
6076 let artifact = print_omena_query_transform_source_with_pretty_options(
6077 source_path,
6078 source.style_source.as_str(),
6079 transform_print_dialect_for_style_path(source_path),
6080 format!("linked-module-source-map-measurement:{source_path}"),
6081 &[],
6082 OmenaQueryTransformPrintOptionsV0 {
6083 mode: OmenaQueryTransformPrintMode::Pretty,
6084 include_source_map: false,
6085 },
6086 OmenaQueryPrettyFormatOptionsV0 {
6087 line_width: 100,
6088 indent_width: 2,
6089 },
6090 );
6091 (
6092 source_path.to_string(),
6093 artifact.css == module.execution.output_css,
6094 )
6095 })
6096 })
6097 .collect::<BTreeMap<_, _>>();
6098 let pretty_render_equal_count = pretty_render_equality
6099 .values()
6100 .filter(|equal| **equal)
6101 .count();
6102 eprintln!(
6103 "linked source-map render census: fixtureCount=1 cstAnchors={} renderedEqual={}",
6104 cst_anchor_count, pretty_render_equal_count
6105 );
6106 carrier_hygiene_assertions::assert_pretty_render_measurement(&pretty_render_equality);
6109
6110 assert!(
6111 segments.len() > transformed.len(),
6112 "segments={}, modules={}, dispositions={dispositions:?}",
6113 segments.len(),
6114 transformed.len()
6115 );
6116 assert_eq!(dispositions.len(), transformed.len());
6117 assert!(dispositions.iter().all(|disposition| {
6118 disposition.granularity == OmenaQueryLinkedSourceMapGranularityV0::CstAnchors
6119 && disposition.fallback_reason.is_none()
6120 }));
6121 for segment in &segments {
6122 let region = materialization
6123 .module_regions
6124 .iter()
6125 .find(|region| region.module_instance.module().as_str() == segment.source_path)
6126 .ok_or_else(|| {
6127 format!(
6128 "source-map segment has no region for {:?}",
6129 segment.source_path
6130 )
6131 })?;
6132 assert!(segment.generated_start >= region.generated_start);
6133 assert!(segment.generated_end <= region.generated_end);
6134 assert!(segment.generated_end > segment.generated_start);
6135 assert_eq!(
6136 segment.generated_start_point.byte_offset,
6137 segment.generated_start
6138 );
6139 assert_eq!(segment.pass_id, "linked-order-emission");
6140 }
6141 for region in &materialization.module_regions {
6142 assert!(segments.iter().any(|segment| {
6143 segment.source_path == region.module_instance.module().as_str()
6144 && segment.original_start > 0
6145 }));
6146 }
6147 let token_lines = segments
6148 .iter()
6149 .filter(|segment| segment.source_path == "src/tokens.css")
6150 .map(|segment| segment.original_start_point.line)
6151 .collect::<BTreeSet<_>>();
6152 assert!(token_lines.len() >= 3);
6153 let third_rule = segments
6154 .iter()
6155 .filter(|segment| segment.source_path == "src/tokens.css")
6156 .find(|segment| segment.original_start_point.line == 2)
6157 .ok_or_else(|| "third token rule should map to its source line".to_string())?;
6158 assert_eq!(third_rule.original_start_point.line, 2);
6159
6160 let entry_instance = linked
6161 .entrypoints
6162 .first()
6163 .ok_or_else(|| "source-map fixture should have an entrypoint".to_string())?;
6164 let mut bundle_execution = module_executions
6165 .iter()
6166 .find(|module| &module.module_instance == entry_instance)
6167 .ok_or_else(|| "source-map fixture should retain its entry execution".to_string())?
6168 .execution
6169 .clone();
6170 bundle_execution.output_byte_len = materialization.output_css.len();
6171 bundle_execution
6172 .output_css
6173 .clone_from(&materialization.output_css);
6174 let (source_map, _) = summarize_omena_query_linked_bundle_source_map_v3(
6175 "src/app.css",
6176 &style_sources,
6177 &bundle_execution,
6178 &materialization,
6179 &module_executions,
6180 )?;
6181 assert_eq!(
6182 source_map.x_omena_pass_ids,
6183 ["linked-order-emission", "print-css"]
6184 );
6185 assert_eq!(
6186 &materialization.output_css[third_rule.generated_start..third_rule.generated_end],
6187 "linked-map-token-c"
6188 );
6189 let generated_point = &third_rule.generated_start_point;
6190 let decoded = decode_source_map_mappings(&source_map.mappings)?;
6191 let decoded_third_rule = decoded
6192 .iter()
6193 .filter(|segment| {
6194 segment.generated_line < generated_point.line
6195 || (segment.generated_line == generated_point.line
6196 && segment.generated_column <= generated_point.utf8_column)
6197 })
6198 .max_by_key(|segment| (segment.generated_line, segment.generated_column))
6199 .ok_or_else(|| "third token rule should have a decoded mapping".to_string())?;
6200 assert_eq!(
6201 source_map.sources[decoded_third_rule.source_index],
6202 "src/tokens.css"
6203 );
6204 assert_eq!(decoded_third_rule.original_line, 2);
6205 Ok(())
6206 }
6207
6208 #[test]
6209 fn linked_bundle_source_map_falls_back_when_module_output_changes() -> Result<(), String> {
6210 let source = "\n .app { color: red; }";
6211 let style_sources = vec![OmenaQueryStyleSourceInputV0 {
6212 style_path: "src/app.css".to_string(),
6213 style_source: source.to_string(),
6214 }];
6215 let modules = vec![TransformBundleModuleInputV0::new(
6216 "src/app.css",
6217 source,
6218 omena_parser::StyleDialect::Css,
6219 )];
6220 let linked = link_omena_transform_bundle_modules(&["src/app.css"], &modules)
6221 .map_err(|error| format!("fallback fixture should link: {error:?}"))?;
6222 let module_instance = linked
6223 .module_instances
6224 .first()
6225 .ok_or_else(|| "fallback fixture should contain one module".to_string())?
6226 .clone();
6227 let transformed = vec![TransformBundleTransformedModuleV0::new(
6228 module_instance.clone(),
6229 ".app{color:red}",
6230 )];
6231 let materialization =
6232 materialize_omena_transform_bundle_linked_stylesheet(&linked, &transformed)
6233 .map_err(|error| format!("fallback fixture should materialize: {error:?}"))?;
6234 let mut execution = execute_omena_query_consumer_build_style_source_with_context(
6235 "src/app.css",
6236 source,
6237 &[],
6238 &TransformExecutionContextV0::default(),
6239 )
6240 .execution;
6241 execution.output_css = ".app{color:red}".to_string();
6242 execution.output_byte_len = execution.output_css.len();
6243 let module_executions = vec![LinkedModuleExecutionV0 {
6244 module_instance,
6245 execution,
6246 class_name_rewrites: Vec::new(),
6247 }];
6248 let (segments, dispositions) = linked_bundle_source_map_segments(
6249 &style_sources,
6250 &materialization.output_css,
6251 &materialization,
6252 &module_executions,
6253 )?;
6254
6255 assert_eq!(segments.len(), 1);
6256 assert_eq!(dispositions.len(), 1);
6257 assert_eq!(
6258 dispositions[0].granularity,
6259 OmenaQueryLinkedSourceMapGranularityV0::WholeModuleFallback
6260 );
6261 assert_eq!(
6262 dispositions[0].fallback_reason,
6263 Some(LINKED_FALLBACK_EXACT_TOKEN_REASON)
6264 );
6265 assert_eq!(segments[0].original_start, 3);
6266 assert_eq!(segments[0].original_end, source.len());
6267 assert_eq!(segments[0].original_start_point.byte_offset, 3);
6268 assert_eq!(segments[0].original_start_point.line, 1);
6269 assert_eq!(segments[0].original_start_point.utf8_column, 2);
6270 #[allow(deprecated)]
6271 let bundle_execution = project_linked_bundle_execution(
6272 module_executions[0].execution.clone(),
6273 materialization.output_css.as_str(),
6274 );
6275 let (source_map, _) = summarize_omena_query_linked_bundle_source_map_v3(
6276 "src/app.css",
6277 &style_sources,
6278 &bundle_execution,
6279 &materialization,
6280 &module_executions,
6281 )?;
6282 let decoded = decode_source_map_mappings(source_map.mappings.as_str())?;
6283 let first_mapping = decoded
6284 .first()
6285 .ok_or_else(|| "fallback should emit a serialized mapping".to_string())?;
6286 assert_eq!(
6287 source_map.sources[first_mapping.source_index],
6288 "src/app.css"
6289 );
6290 assert_eq!(first_mapping.original_line, 1);
6291 assert_eq!(first_mapping.original_column, 2);
6292 Ok(())
6293 }
6294
6295 #[test]
6296 fn linked_bundle_source_map_fallback_anchors_surviving_tokens_after_removed_import()
6297 -> Result<(), String> {
6298 let source = "@import \"./tokens.css\";\n.app { color: red; }";
6299 let generated = ".app{color:red}";
6300 let (segment, reason) =
6301 linked_whole_module_fallback_segment("src/app.css", source, generated);
6302 assert_eq!(reason, LINKED_FALLBACK_EXACT_TOKEN_REASON);
6303 assert_eq!(
6304 &source[segment.original_start..segment.original_end],
6305 ".app { color: red; }"
6306 );
6307 validate_linked_source_map_original_segment(
6308 "src/app.css",
6309 source,
6310 generated,
6311 &segment,
6312 OmenaQueryLinkedSourceMapGranularityV0::WholeModuleFallback,
6313 Some(reason),
6314 )
6315 }
6316
6317 #[test]
6318 fn linked_bundle_source_map_fallback_discloses_source_start_without_correspondence()
6319 -> Result<(), String> {
6320 let source = "@import \"./tokens.css\";\n .app { color: red; }";
6321 let generated = "._app_0{color:blue}";
6322 let (segment, reason) =
6323 linked_whole_module_fallback_segment("src/app.css", source, generated);
6324 assert_eq!(reason, LINKED_FALLBACK_SOURCE_START_REASON);
6325 assert_eq!(&source[segment.original_start..], ".app { color: red; }");
6326 assert_eq!(segment.original_end, source.len());
6327 validate_linked_source_map_original_segment(
6328 "src/app.css",
6329 source,
6330 generated,
6331 &segment,
6332 OmenaQueryLinkedSourceMapGranularityV0::WholeModuleFallback,
6333 Some(reason),
6334 )
6335 }
6336
6337 #[test]
6338 fn linked_bundle_source_map_fallback_discloses_ambiguous_surviving_tokens() -> Result<(), String>
6339 {
6340 let fixture: serde_json::Value = serde_json::from_str(include_str!(
6341 "../../tests/fixtures/linked-source-map-fallback-ambiguity.json"
6342 ))
6343 .map_err(|error| error.to_string())?;
6344 let source_path = fixture["sourcePath"]
6345 .as_str()
6346 .ok_or_else(|| "ambiguity fixture has no sourcePath".to_string())?;
6347 let source = fixture["source"]
6348 .as_str()
6349 .ok_or_else(|| "ambiguity fixture has no source".to_string())?;
6350 let generated = fixture["generated"]
6351 .as_str()
6352 .ok_or_else(|| "ambiguity fixture has no generated output".to_string())?;
6353 let source_tokens = canonical_linked_fallback_tokens(
6354 lex_omena_query_omena_parser_style_source(source, omena_parser::StyleDialect::Css)
6355 .tokens(),
6356 )
6357 .iter()
6358 .map(|token| format!("{:?}:{}", token.kind, token.text))
6359 .collect::<Vec<_>>();
6360 let generated_tokens = canonical_linked_fallback_tokens(
6361 lex_omena_query_omena_parser_style_source(generated, omena_parser::StyleDialect::Css)
6362 .tokens(),
6363 )
6364 .iter()
6365 .map(|token| format!("{:?}:{}", token.kind, token.text))
6366 .collect::<Vec<_>>();
6367 assert_eq!(
6368 serde_json::to_value(&source_tokens).map_err(|error| error.to_string())?,
6369 fixture["sourceTokens"]
6370 );
6371 assert_eq!(
6372 serde_json::to_value(&generated_tokens).map_err(|error| error.to_string())?,
6373 fixture["generatedTokens"]
6374 );
6375 let matching_window_starts = source_tokens
6376 .windows(generated_tokens.len())
6377 .enumerate()
6378 .filter_map(|(index, window)| (window == generated_tokens).then_some(index))
6379 .collect::<Vec<_>>();
6380 assert_eq!(
6381 serde_json::to_value(&matching_window_starts).map_err(|error| error.to_string())?,
6382 fixture["matchingWindowStarts"]
6383 );
6384
6385 let style_sources = vec![OmenaQueryStyleSourceInputV0 {
6386 style_path: source_path.to_string(),
6387 style_source: source.to_string(),
6388 }];
6389 let modules = vec![TransformBundleModuleInputV0::new(
6390 source_path,
6391 source,
6392 omena_parser::StyleDialect::Css,
6393 )];
6394 let linked = link_omena_transform_bundle_modules(&[source_path], &modules)
6395 .map_err(|error| format!("ambiguity fixture should link: {error:?}"))?;
6396 let module_instance = linked
6397 .module_instances
6398 .first()
6399 .ok_or_else(|| "ambiguity fixture should contain one module".to_string())?
6400 .clone();
6401 let transformed = vec![TransformBundleTransformedModuleV0::new(
6402 module_instance.clone(),
6403 generated,
6404 )];
6405 let materialization =
6406 materialize_omena_transform_bundle_linked_stylesheet(&linked, &transformed)
6407 .map_err(|error| format!("ambiguity fixture should materialize: {error:?}"))?;
6408 let mut execution = execute_omena_query_consumer_build_style_source_with_context(
6409 source_path,
6410 source,
6411 &[],
6412 &TransformExecutionContextV0::default(),
6413 )
6414 .execution;
6415 execution.output_css = generated.to_string();
6416 execution.output_byte_len = generated.len();
6417 let module_executions = vec![LinkedModuleExecutionV0 {
6418 module_instance,
6419 execution,
6420 class_name_rewrites: Vec::new(),
6421 }];
6422 let (segments, dispositions) = linked_bundle_source_map_segments(
6423 &style_sources,
6424 &materialization.output_css,
6425 &materialization,
6426 &module_executions,
6427 )?;
6428 assert_eq!(segments.len(), 1);
6429 assert_eq!(dispositions.len(), 1);
6430 let segment = &segments[0];
6431 let (segment, reason) = (
6432 segment,
6433 dispositions[0]
6434 .fallback_reason
6435 .ok_or_else(|| "ambiguity fixture should disclose a fallback reason".to_string())?,
6436 );
6437 assert_eq!(reason, LINKED_FALLBACK_AMBIGUOUS_TOKEN_REASON);
6438 assert_eq!(
6439 serde_json::json!({
6440 "originalStart": segment.original_start,
6441 "originalEnd": segment.original_end,
6442 "generatedStart": segment.generated_start,
6443 "generatedEnd": segment.generated_end,
6444 }),
6445 fixture["expectedSegment"]
6446 );
6447 validate_linked_source_map_original_segment(
6448 source_path,
6449 source,
6450 generated,
6451 segment,
6452 OmenaQueryLinkedSourceMapGranularityV0::WholeModuleFallback,
6453 Some(reason),
6454 )
6455 }
6456
6457 #[test]
6458 fn linked_bundle_source_map_validator_rejects_exact_claim_for_ambiguous_tokens() {
6459 let source = ".app { color: red; }\n.app { color: red; }";
6460 let generated = ".app{color:red}";
6461 let segment = TransformSourceMapSegmentV0 {
6462 source_path: "src/app.css".to_string(),
6463 original_start: 0,
6464 original_end: 20,
6465 generated_start: 0,
6466 generated_end: generated.len(),
6467 original_start_point: transform_source_map_point(source, 0),
6468 original_end_point: transform_source_map_point(source, 20),
6469 generated_start_point: transform_source_map_point(generated, 0),
6470 generated_end_point: transform_source_map_point(generated, generated.len()),
6471 pass_id: "linked-order-emission",
6472 };
6473 let result = validate_linked_source_map_original_segment(
6474 "src/app.css",
6475 source,
6476 generated,
6477 &segment,
6478 OmenaQueryLinkedSourceMapGranularityV0::WholeModuleFallback,
6479 Some(LINKED_FALLBACK_EXACT_TOKEN_REASON),
6480 );
6481 assert!(result.is_err());
6482 let error = result.err().unwrap_or_default();
6483 assert!(error.contains("without one unique matching token window"));
6484 }
6485}
6486
6487#[cfg(test)]
6488mod dependency_resolution_tests {
6489 use super::*;
6490
6491 fn configured_sass_sources() -> Vec<OmenaQueryStyleSourceInputV0> {
6492 vec![
6493 OmenaQueryStyleSourceInputV0 {
6494 style_path: "src/blue.scss".to_string(),
6495 style_source:
6496 r#"@use "./theme" with ($brand: blue); .blue { color: theme.$brand; }"#
6497 .to_string(),
6498 },
6499 OmenaQueryStyleSourceInputV0 {
6500 style_path: "src/red.scss".to_string(),
6501 style_source: r#"@use "./theme" with ($brand: red); .red { color: theme.$brand; }"#
6502 .to_string(),
6503 },
6504 OmenaQueryStyleSourceInputV0 {
6505 style_path: "src/theme.scss".to_string(),
6506 style_source:
6507 "$brand: black !default; .kept { color: $brand; } .dead { color: gray; }"
6508 .to_string(),
6509 },
6510 ]
6511 }
6512
6513 #[test]
6514 fn linker_projection_records_resolver_attempt_provenance() {
6515 let sources = vec![
6516 OmenaQueryStyleSourceInputV0 {
6517 style_path: "src/app.css".to_string(),
6518 style_source: r#"@import "@acme/theme/tokens.css"; .app { color: green; }"#
6519 .to_string(),
6520 },
6521 OmenaQueryStyleSourceInputV0 {
6522 style_path: "node_modules/@acme/theme/dist/tokens.css".to_string(),
6523 style_source: ".token { color: rebeccapurple; }".to_string(),
6524 },
6525 ];
6526 let resolution_inputs = OmenaQueryStyleResolutionInputsV0 {
6527 package_manifests: vec![OmenaQueryStylePackageManifestV0 {
6528 package_json_path: "node_modules/@acme/theme/package.json".to_string(),
6529 package_json_source:
6530 r#"{"name":"@acme/theme","exports":{"./tokens.css":"./dist/tokens.css"}}"#
6531 .to_string(),
6532 }],
6533 ..OmenaQueryStyleResolutionInputsV0::default()
6534 };
6535 let prepared = prepare_transform_bundle_linker_projection(
6536 &["src/app.css"],
6537 &sources,
6538 &[],
6539 TransformResolutionContext::from_resolution_inputs(&resolution_inputs),
6540 );
6541 let resolved = prepared.resolved_dependencies;
6542
6543 assert_eq!(resolved.len(), 1);
6544 assert_eq!(resolved[0].resolution.attempt_state, "attempted");
6545 assert_eq!(
6546 resolved[0].resolution.resolution_kind,
6547 Some("packageStyleModule")
6548 );
6549 assert_eq!(
6550 resolved[0].resolution.policy_step_keys,
6551 vec![
6552 "externalUrlBoundary",
6553 "bundlerPathMapping",
6554 "tsconfigPathMapping",
6555 "sassPkgImporter",
6556 "fileRelativeOrAbsolute",
6557 "packageManifestSubpath",
6558 "nodePackageFallback",
6559 "sassLoadPathRoot",
6560 ]
6561 );
6562 assert_eq!(
6563 resolved[0].resolution.target_instance,
6564 prepared
6565 .projection
6566 .inputs()
6567 .iter()
6568 .find(|input| { input.source_path == "node_modules/@acme/theme/dist/tokens.css" })
6569 .map(|input| input.instance.clone())
6570 );
6571 }
6572
6573 #[test]
6574 fn linked_default_resolves_explicit_relative_extension_in_memory() -> Result<(), String> {
6575 let sources = vec![
6576 OmenaQueryStyleSourceInputV0 {
6577 style_path: "linked-byte/css/app.css".to_string(),
6578 style_source: r#"@import "./z.css"; @import "./a.css"; .app { color: green; }"#
6579 .to_string(),
6580 },
6581 OmenaQueryStyleSourceInputV0 {
6582 style_path: "linked-byte/css/z.css".to_string(),
6583 style_source: ".token { color: rebeccapurple; }".to_string(),
6584 },
6585 OmenaQueryStyleSourceInputV0 {
6586 style_path: "linked-byte/css/a.css".to_string(),
6587 style_source: ".base { color: blue; }".to_string(),
6588 },
6589 ];
6590 let resolution_inputs = OmenaQueryStyleResolutionInputsV0::default();
6591 let prepared = prepare_transform_bundle_linker_projection(
6592 &["linked-byte/css/app.css"],
6593 &sources,
6594 &[],
6595 TransformResolutionContext::from_resolution_inputs(&resolution_inputs),
6596 );
6597 assert_eq!(prepared.resolved_dependencies.len(), 2);
6598 assert_eq!(
6599 prepared
6600 .resolved_dependencies
6601 .iter()
6602 .filter_map(|dependency| dependency.resolution.target_instance.as_ref())
6603 .map(|instance| instance.module().as_str())
6604 .collect::<BTreeSet<_>>(),
6605 BTreeSet::from(["linked-byte/css/a.css", "linked-byte/css/z.css"])
6606 );
6607 link_omena_transform_bundle_projection_with_resolved_dependencies_and_options(
6608 &["linked-byte/css/app.css"],
6609 &prepared.projection,
6610 prepared.resolved_dependencies.as_slice(),
6611 &[],
6612 TransformBundleLinkOptionsV0::default(),
6613 )
6614 .map_err(|error| format!("linked default should resolve the in-memory edge: {error:?}"))?;
6615 Ok(())
6616 }
6617
6618 #[test]
6619 #[allow(deprecated)]
6620 fn configured_sass_edges_select_distinct_instances_without_reparsing() -> Result<(), String> {
6621 let sources = configured_sass_sources();
6622 let resolution_inputs = OmenaQueryStyleResolutionInputsV0::default();
6623 let mut reachability = TransformBundleSemanticReachabilityInputV0::new("src/theme.scss");
6624 reachability.class_names.push("kept".to_string());
6625 let (prepared, parser_snapshot) =
6626 omena_parser::with_omena_parser_parse_instrumentation(|| {
6627 prepare_transform_bundle_linker_projection(
6628 &["src/blue.scss", "src/red.scss"],
6629 &sources,
6630 std::slice::from_ref(&reachability),
6631 TransformResolutionContext::from_resolution_inputs(&resolution_inputs),
6632 )
6633 });
6634
6635 assert_eq!(parser_snapshot.parse_invocation_count, 3);
6636 let theme_inputs = prepared
6637 .projection
6638 .inputs()
6639 .iter()
6640 .filter(|input| input.source_path == "src/theme.scss")
6641 .collect::<Vec<_>>();
6642 eprintln!(
6643 "instance reachability fan-out: expectedConfigurations={} emittedRows={}",
6644 prepared.expected_instance_reachability_count,
6645 prepared.emitted_instance_reachability_count
6646 );
6647 let reachability_derivations = theme_inputs
6648 .iter()
6649 .map(|input| {
6650 prepared
6651 .projection
6652 .module_reachability_derivation(&input.instance)
6653 })
6654 .collect::<Vec<_>>();
6655 carrier_hygiene_assertions::assert_instance_reachability_fan_out(
6656 prepared.expected_instance_reachability_count,
6657 prepared.emitted_instance_reachability_count,
6658 reachability_derivations.as_slice(),
6659 );
6660 assert_eq!(
6661 theme_inputs
6662 .iter()
6663 .map(|input| input.instance.configuration().as_str())
6664 .collect::<BTreeSet<_>>(),
6665 BTreeSet::from(["with|5:brand=3:red", "with|5:brand=4:blue"])
6666 );
6667 assert!(theme_inputs.iter().all(|input| {
6668 input.class_names == ["kept".to_string()]
6669 && !input.class_names.contains(&"dead".to_string())
6670 }));
6671
6672 let target_by_source = prepared
6673 .resolved_dependencies
6674 .iter()
6675 .map(|dependency| {
6676 (
6677 dependency.source_instance.module().as_str(),
6678 dependency
6679 .resolution
6680 .target_instance
6681 .as_ref()
6682 .map(|instance| instance.configuration().as_str()),
6683 )
6684 })
6685 .collect::<BTreeMap<_, _>>();
6686 assert_eq!(
6687 target_by_source.get("src/blue.scss").copied().flatten(),
6688 Some("with|5:brand=4:blue")
6689 );
6690 assert_eq!(
6691 target_by_source.get("src/red.scss").copied().flatten(),
6692 Some("with|5:brand=3:red")
6693 );
6694
6695 let expected_resolution_count = prepared
6696 .projection
6697 .inputs()
6698 .iter()
6699 .map(|input| input.dependency_edges.len())
6700 .sum::<usize>();
6701 let strict = link_resolved_bundle(
6702 &["src/blue.scss", "src/red.scss"],
6703 &prepared.projection,
6704 &prepared.emission_item_projection,
6705 prepared.resolved_dependencies.as_slice(),
6706 &[],
6707 EmissionOrderingPolicyV0::ModuleIdLegacy,
6708 )
6709 .map_err(|error| format!("configured Sass producer should close every edge: {error:?}"))?;
6710 let legacy_resolution_count = strict
6711 .dependency_resolution_disclosures
6712 .iter()
6713 .filter(|disclosure| {
6714 disclosure.authority == BundleResolutionAuthorityV0::LegacyPathInferred
6715 })
6716 .count();
6717 eprintln!(
6718 "resolution authority census: expectedEdges={} disclosedEdges={} legacyEdges={}",
6719 expected_resolution_count,
6720 strict.dependency_resolution_disclosures.len(),
6721 legacy_resolution_count
6722 );
6723 carrier_hygiene_assertions::assert_resolution_authority_census(
6724 expected_resolution_count,
6725 strict.dependency_resolution_disclosures.len(),
6726 legacy_resolution_count,
6727 );
6728
6729 let linked = link_omena_transform_bundle_projection_with_resolved_dependencies_and_options(
6730 &["src/blue.scss", "src/red.scss"],
6731 &prepared.projection,
6732 prepared.resolved_dependencies.as_slice(),
6733 &[],
6734 TransformBundleLinkOptionsV0::default(),
6735 )
6736 .map_err(|error| format!("configured Sass workspace should link: {error:?}"))?;
6737 assert_eq!(
6738 linked
6739 .module_instances
6740 .iter()
6741 .filter(|instance| instance.module().as_str() == "src/theme.scss")
6742 .count(),
6743 2
6744 );
6745 Ok(())
6746 }
6747
6748 #[test]
6749 fn configured_module_path_can_also_be_an_unconfigured_entrypoint() -> Result<(), String> {
6750 let sources = configured_sass_sources();
6751 let resolution_inputs = OmenaQueryStyleResolutionInputsV0::default();
6752 let prepared = prepare_transform_bundle_linker_projection(
6753 &["src/blue.scss", "src/red.scss", "src/theme.scss"],
6754 &sources,
6755 &[],
6756 TransformResolutionContext::from_resolution_inputs(&resolution_inputs),
6757 );
6758 let linked = link_omena_transform_bundle_projection_with_resolved_dependencies_and_options(
6759 &["src/blue.scss", "src/red.scss", "src/theme.scss"],
6760 &prepared.projection,
6761 prepared.resolved_dependencies.as_slice(),
6762 &[],
6763 TransformBundleLinkOptionsV0::default(),
6764 )
6765 .map_err(|error| format!("configured module entrypoint should link: {error:?}"))?;
6766
6767 let theme_entrypoint = linked
6768 .entrypoints
6769 .iter()
6770 .find(|entrypoint| entrypoint.module().as_str() == "src/theme.scss")
6771 .ok_or_else(|| "theme entrypoint was not selected".to_string())?;
6772 assert_eq!(
6773 theme_entrypoint.configuration(),
6774 &omena_parser::ConfigurationHashV0::none()
6775 );
6776 Ok(())
6777 }
6778
6779 #[test]
6780 fn unconfigured_projection_preserves_closure_identity() -> Result<(), String> {
6781 let sources = vec![
6782 OmenaQueryStyleSourceInputV0 {
6783 style_path: "src/app.css".to_string(),
6784 style_source: r#"@import "./theme.css"; .app { color: green; }"#.to_string(),
6785 },
6786 OmenaQueryStyleSourceInputV0 {
6787 style_path: "src/theme.css".to_string(),
6788 style_source: ".theme { color: rebeccapurple; }".to_string(),
6789 },
6790 ];
6791 let legacy_modules = sources
6792 .iter()
6793 .map(|source| {
6794 TransformBundleModuleInputV0::new(
6795 source.style_path.as_str(),
6796 source.style_source.as_str(),
6797 omena_parser::StyleDialect::Css,
6798 )
6799 })
6800 .collect::<Vec<_>>();
6801 let legacy = link_omena_transform_bundle_modules(&["src/app.css"], &legacy_modules)
6802 .map_err(|error| format!("legacy unconfigured fixture should link: {error:?}"))?;
6803 let resolution_inputs = OmenaQueryStyleResolutionInputsV0::default();
6804 let prepared = prepare_transform_bundle_linker_projection(
6805 &["src/app.css"],
6806 &sources,
6807 &[],
6808 TransformResolutionContext::from_resolution_inputs(&resolution_inputs),
6809 );
6810 let current =
6811 link_omena_transform_bundle_projection_with_resolved_dependencies_and_options(
6812 &["src/app.css"],
6813 &prepared.projection,
6814 prepared.resolved_dependencies.as_slice(),
6815 &[],
6816 TransformBundleLinkOptionsV0::default(),
6817 )
6818 .map_err(|error| format!("prepared unconfigured fixture should link: {error:?}"))?;
6819
6820 assert_eq!(current.module_instances, legacy.module_instances);
6821 assert_eq!(
6822 current.closed_world_bundle.closure_hash(),
6823 legacy.closed_world_bundle.closure_hash()
6824 );
6825 Ok(())
6826 }
6827}
6828
6829#[cfg(test)]
6830mod closed_world_link_error_tests {
6831 use super::closed_world_blocker_from_link_error;
6832 use crate::OmenaQueryClosedWorldBlockerV0;
6833 use omena_query_transform_runner::{
6834 EmissionCycleClassV0, EmissionCycleDialectV0, TransformBundleEdgeKind,
6835 TransformBundleLinkErrorV0,
6836 };
6837
6838 #[test]
6839 fn engine_only_emission_failures_preserve_product_evidence() -> Result<(), String> {
6840 let requested_pass_ids = vec!["tree-shake".to_string()];
6841 let expected = OmenaQueryClosedWorldBlockerV0::ClosedWorldPassUnavailable {
6842 requested_pass_ids: requested_pass_ids.clone(),
6843 };
6844
6845 for error in [
6846 TransformBundleLinkErrorV0::InvalidEmissionPlan {
6847 reason: "duplicate order key".to_string(),
6848 },
6849 TransformBundleLinkErrorV0::UnsupportedEmissionCycle {
6850 edge_kind: TransformBundleEdgeKind::SassUse,
6851 },
6852 ] {
6853 assert_eq!(
6854 closed_world_blocker_from_link_error(error, &requested_pass_ids),
6855 expected
6856 );
6857 }
6858
6859 let dialect_cycle = TransformBundleLinkErrorV0::UnsupportedDialectEmissionCycle {
6860 dialect: EmissionCycleDialectV0::Scss,
6861 class: EmissionCycleClassV0::Import,
6862 edge_kinds: vec![TransformBundleEdgeKind::SassUse],
6863 };
6864 let projected = closed_world_blocker_from_link_error(dialect_cycle, &requested_pass_ids);
6865 assert_eq!(
6866 projected,
6867 OmenaQueryClosedWorldBlockerV0::UnsupportedDialectEmissionCycle {
6868 dialect: EmissionCycleDialectV0::Scss,
6869 class: EmissionCycleClassV0::Import,
6870 edge_kinds: vec![TransformBundleEdgeKind::SassUse],
6871 }
6872 );
6873 let serialized = serde_json::to_value(&projected).map_err(|error| error.to_string())?;
6874 assert_eq!(
6875 serialized,
6876 serde_json::json!({
6877 "kind": "unsupportedDialectEmissionCycle",
6878 "dialect": "scss",
6879 "class": "import",
6880 "edgeKinds": ["sassUse"],
6881 })
6882 );
6883 Ok(())
6884 }
6885}
6886
6887#[cfg(test)]
6888mod closed_set_precision_tests {
6889 use super::*;
6890
6891 #[test]
6892 fn sealed_bundle_content_binds_finite_reachability_precision() -> Result<(), String> {
6893 let style_path = "Workspace.module.css";
6894 let style_source = ".card {} .panel {} .toolbar {} .dead {}";
6895 let reachable_class_names = vec![
6896 "card".to_string(),
6897 "panel".to_string(),
6898 "toolbar".to_string(),
6899 ];
6900 let context = TransformExecutionContextV0 {
6901 reachable_class_names: reachable_class_names.clone(),
6902 ..TransformExecutionContextV0::default()
6903 };
6904 let requested_pass_ids = vec!["tree-shake-class".to_string()];
6905 let bundle = build_closed_world_bundle_for_single_style_source_context(
6906 style_path,
6907 style_source,
6908 &requested_pass_ids,
6909 &context,
6910 )
6911 .ok_or_else(|| {
6912 "the finite reachability fixture should produce a sealed bundle".to_string()
6913 })?;
6914 let finite_value = AbstractClassValueV0::FiniteSet {
6915 values: reachable_class_names,
6916 };
6917 let open_world_precision = fact_precision_from_class_value(&finite_value);
6918 let closed_world_precision = closed_world_bound_reachability_precision(
6919 &context,
6920 &bundle,
6921 Some(open_world_precision),
6922 true,
6923 );
6924 let non_enumerated_precision = closed_world_bound_reachability_precision(
6925 &context,
6926 &bundle,
6927 Some(open_world_precision),
6928 false,
6929 );
6930 let missing_member_context = TransformExecutionContextV0 {
6931 reachable_class_names: vec!["card".to_string(), "outside-bundle".to_string()],
6932 ..TransformExecutionContextV0::default()
6933 };
6934 let missing_member_precision = closed_world_bound_reachability_precision(
6935 &missing_member_context,
6936 &bundle,
6937 Some(open_world_precision),
6938 true,
6939 );
6940
6941 assert_eq!(open_world_precision, FactPrecision::Conservative);
6942 assert_eq!(closed_world_precision, FactPrecision::Exact);
6943 assert_eq!(non_enumerated_precision, FactPrecision::Conservative);
6944 assert_eq!(missing_member_precision, FactPrecision::Conservative);
6945
6946 let calibration_report: serde_json::Value = serde_json::from_str(include_str!(
6947 "../../../../omena-precision-calibration-report.json"
6948 ))
6949 .map_err(|error| format!("precision calibration report should be valid JSON: {error}"))?;
6950 assert_eq!(
6951 calibration_report["cases"][1],
6952 serde_json::json!({
6953 "caseId": "closedSetFiniteReachability",
6954 "inputClassCount": 3,
6955 "representation": "finiteSet",
6956 "witnessDirection": "supersetOfProducible",
6957 "witnessBasis": "closedSetEnumeration",
6958 "authority": "closedWorldBundleClosureHash",
6959 "openWorldPrecision": open_world_precision,
6960 "closedWorldPrecision": closed_world_precision,
6961 "nonEnumeratedPrecision": non_enumerated_precision,
6962 "missingMemberPrecision": missing_member_precision,
6963 })
6964 );
6965 Ok(())
6966 }
6967}