Skip to main content

omena_transform_passes/runtime/
planner.rs

1//! Transform pass registry, DAG planner, and public boundary summary.
2//!
3//! Planner code maps `omena-transform-cst` pass contracts into executable
4//! registry entries, enforces default DAG ordering, and reports the mutation
5//! passes that are implemented by the runtime executor.
6
7use omena_transform_cst::{
8    TRANSFORM_PASS_CATALOG_LEN, TransformDagEdgeV0, TransformLayer, TransformPassContractV0,
9    TransformPassKind, all_transform_pass_kinds, default_transform_dag_edges,
10    default_transform_pass_contracts,
11};
12
13use crate::{
14    TransformPassExecutionStatus, TransformPassPlanV0, TransformPassRegistryEntryV0,
15    TransformPassesBoundarySummaryV0,
16};
17
18pub fn summarize_omena_transform_passes_boundary() -> TransformPassesBoundarySummaryV0 {
19    let registry_entries = default_transform_pass_contracts()
20        .into_iter()
21        .map(registry_entry_for_contract)
22        .collect::<Vec<_>>();
23    let pass_count = registry_entries.len();
24    let semantic_aware_pass_count = registry_entries
25        .iter()
26        .filter(|entry| entry.contract.layer == TransformLayer::SemanticAware)
27        .count();
28    let cascade_aware_pass_count = registry_entries
29        .iter()
30        .filter(|entry| entry.contract.reads_cascade_model)
31        .count();
32
33    TransformPassesBoundarySummaryV0 {
34        schema_version: "0",
35        product: "omena-transform-passes.boundary",
36        registry_entries,
37        dag_edges: default_transform_dag_edges(),
38        pass_count,
39        full_catalog_registered: pass_count == TRANSFORM_PASS_CATALOG_LEN,
40        semantic_aware_pass_count,
41        cascade_aware_pass_count,
42        planner_enforces_dag_edges: true,
43        execution_runtime_ready: true,
44        incremental_execution_runtime_ready: true,
45        implemented_mutation_pass_ids: implemented_mutation_pass_ids(),
46        next_surfaces: Vec::new(),
47    }
48}
49
50pub fn plan_transform_passes(requested: &[TransformPassKind]) -> TransformPassPlanV0 {
51    let requested_pass_ids = requested.iter().map(|pass| pass.id()).collect::<Vec<_>>();
52    let ordered_passes = order_passes_by_dag(requested);
53    let ordered_pass_ids = ordered_passes
54        .iter()
55        .map(|pass| pass.id())
56        .collect::<Vec<_>>();
57    let dag_edges = default_transform_dag_edges();
58    let satisfied_dag_edge_count = dag_edges
59        .iter()
60        .filter(|edge| {
61            edge_applies(edge, &ordered_pass_ids) && edge_is_satisfied(edge, &ordered_pass_ids)
62        })
63        .count();
64    let violated_dag_edge_count = dag_edges
65        .iter()
66        .filter(|edge| {
67            edge_applies(edge, &ordered_pass_ids) && !edge_is_satisfied(edge, &ordered_pass_ids)
68        })
69        .count();
70
71    TransformPassPlanV0 {
72        schema_version: "0",
73        product: "omena-transform-passes.plan",
74        requested_pass_ids,
75        ordered_pass_ids,
76        satisfied_dag_edge_count,
77        violated_dag_edge_count,
78        all_requested_registered: requested.iter().all(pass_is_registered),
79    }
80}
81
82#[cfg(feature = "lawvere-trace")]
83pub fn plan_transform_passes_parallel_lawvere_layers(
84    requested: &[TransformPassKind],
85) -> omena_lawvere::TransformPassParallelPlanV0 {
86    omena_lawvere::plan_transform_pass_parallel_layers_v0(requested)
87}
88
89pub fn implemented_mutation_pass_ids() -> Vec<&'static str> {
90    vec![
91        TransformPassKind::WhitespaceStrip.id(),
92        TransformPassKind::CommentStrip.id(),
93        TransformPassKind::NumberCompression.id(),
94        TransformPassKind::UnitNormalization.id(),
95        TransformPassKind::ColorCompression.id(),
96        TransformPassKind::UrlQuoteStrip.id(),
97        TransformPassKind::StringQuoteNormalize.id(),
98        TransformPassKind::SelectorIsWhereCompression.id(),
99        TransformPassKind::ShorthandCombining.id(),
100        TransformPassKind::RuleDeduplication.id(),
101        TransformPassKind::RuleMerging.id(),
102        TransformPassKind::SelectorMerging.id(),
103        TransformPassKind::EmptyRuleRemoval.id(),
104        TransformPassKind::VendorPrefixing.id(),
105        TransformPassKind::LightDarkLowering.id(),
106        TransformPassKind::ColorMixLowering.id(),
107        TransformPassKind::OklchOklabLowering.id(),
108        TransformPassKind::ColorFunctionLowering.id(),
109        TransformPassKind::LogicalToPhysical.id(),
110        TransformPassKind::NestingUnwrap.id(),
111        TransformPassKind::ScopeFlatten.id(),
112        TransformPassKind::LayerFlatten.id(),
113        TransformPassKind::SupportsStaticEval.id(),
114        TransformPassKind::MediaStaticEval.id(),
115        TransformPassKind::DeadMediaBranchRemoval.id(),
116        TransformPassKind::DeadSupportsBranchRemoval.id(),
117        TransformPassKind::ImportInline.id(),
118        TransformPassKind::ScssModuleEvaluate.id(),
119        TransformPassKind::LessModuleEvaluate.id(),
120        TransformPassKind::ValueResolution.id(),
121        TransformPassKind::StaticVarSubstitution.id(),
122        TransformPassKind::ResolveCssModulesComposes.id(),
123        TransformPassKind::HashCssModuleClassNames.id(),
124        TransformPassKind::TreeShakeClass.id(),
125        TransformPassKind::TreeShakeKeyframes.id(),
126        TransformPassKind::TreeShakeValue.id(),
127        TransformPassKind::TreeShakeCustomProperty.id(),
128        TransformPassKind::DesignTokenRouting.id(),
129        TransformPassKind::CalcReduction.id(),
130        TransformPassKind::PrintCss.id(),
131    ]
132}
133
134fn registry_entry_for_contract(contract: TransformPassContractV0) -> TransformPassRegistryEntryV0 {
135    TransformPassRegistryEntryV0 {
136        module_family: module_family_for_pass(contract.kind),
137        query_family: query_family_for_pass(contract.kind),
138        execution_status: TransformPassExecutionStatus::RegistryAndPlannerReady,
139        contract,
140    }
141}
142
143fn module_family_for_pass(kind: TransformPassKind) -> &'static str {
144    match kind.ordinal() {
145        1..=7 => "commodity-token",
146        8 | 25 => "egg-backed",
147        9..=13 => "cascade-proven-structural",
148        14..=24 => "target-lowering",
149        26..=28 => "module-bundle",
150        29..=32 => "css-modules-resolution",
151        33..=39 => "semantic-reachability",
152        40 => "emission",
153        _ => "unknown",
154    }
155}
156
157fn query_family_for_pass(kind: TransformPassKind) -> &'static str {
158    match kind.layer() {
159        TransformLayer::SemanticAware => "semantic-aware-transform-query",
160        TransformLayer::Commodity => "commodity-transform-query",
161        TransformLayer::Emission => "emission-transform-query",
162        TransformLayer::SemanticReadOnly => "semantic-read-only-query",
163    }
164}
165
166fn order_passes_by_dag(requested: &[TransformPassKind]) -> Vec<TransformPassKind> {
167    let mut remaining = dedupe_requested_passes(requested);
168    remaining.sort_by_key(|kind| (execution_rank(*kind), kind.ordinal()));
169
170    let mut ordered = Vec::with_capacity(remaining.len());
171    while !remaining.is_empty() {
172        let next_index = remaining
173            .iter()
174            .position(|candidate| !has_incoming_edge_from_remaining(*candidate, &remaining))
175            .unwrap_or_default();
176        ordered.push(remaining.remove(next_index));
177    }
178
179    ordered
180}
181
182fn dedupe_requested_passes(requested: &[TransformPassKind]) -> Vec<TransformPassKind> {
183    let mut unique = Vec::new();
184    for pass in requested {
185        if !unique.contains(pass) {
186            unique.push(*pass);
187        }
188    }
189    unique
190}
191
192fn has_incoming_edge_from_remaining(
193    candidate: TransformPassKind,
194    remaining: &[TransformPassKind],
195) -> bool {
196    default_transform_dag_edges().iter().any(|edge| {
197        edge.to == candidate.id()
198            && remaining
199                .iter()
200                .any(|other| other.id() == edge.from && *other != candidate)
201    })
202}
203
204fn edge_applies(edge: &TransformDagEdgeV0, ordered_pass_ids: &[&'static str]) -> bool {
205    ordered_pass_ids.contains(&edge.from) && ordered_pass_ids.contains(&edge.to)
206}
207
208fn edge_is_satisfied(edge: &TransformDagEdgeV0, ordered_pass_ids: &[&'static str]) -> bool {
209    let from = position_of_pass_id(edge.from, ordered_pass_ids);
210    let to = position_of_pass_id(edge.to, ordered_pass_ids);
211    match (from, to) {
212        (Some(from), Some(to)) => from < to,
213        _ => false,
214    }
215}
216
217fn position_of_pass_id(pass_id: &'static str, ordered_pass_ids: &[&'static str]) -> Option<usize> {
218    ordered_pass_ids
219        .iter()
220        .position(|ordered_pass_id| *ordered_pass_id == pass_id)
221}
222
223fn pass_is_registered(pass: &TransformPassKind) -> bool {
224    default_transform_pass_contracts()
225        .iter()
226        .any(|contract| contract.kind == *pass)
227}
228
229pub(crate) fn transform_pass_kind_from_id(pass_id: &str) -> Option<TransformPassKind> {
230    all_transform_pass_kinds()
231        .into_iter()
232        .find(|kind| kind.id() == pass_id)
233}
234
235fn execution_rank(kind: TransformPassKind) -> u8 {
236    match kind.ordinal() {
237        26..=28 => 10,
238        29..=39 => 20,
239        14..=24 => 30,
240        8..=13 | 25 => 40,
241        1..=7 => 50,
242        40 => 60,
243        _ => 70,
244    }
245}