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