Skip to main content

omena_query_transform_runner/
lib.rs

1//! Transform-runner boundary for the `omena-query` facade.
2//!
3//! `omena-query` remains the consumer-facing analysis facade, but it should not
4//! directly depend on every transform-family crate. This boundary groups the
5//! transform planner, executor, target planner, printer, and egg witness surface
6//! behind one dependency while preserving the existing query API.
7
8use serde::Serialize;
9
10mod plugin_api;
11mod plugins;
12
13pub use plugin_api::*;
14pub use plugins::{built_in_omena_plugins, execute_built_in_omena_plugin};
15
16#[allow(deprecated)]
17pub use omena_bundler::{
18    BundleDependencyResolutionDisclosureV0, BundleResolutionAuthorityV0, EmissionOrderingPolicyV0,
19    InstanceReachabilityDerivationV0, LinkedEmissionArtifactV0,
20    LinkedEmissionItemMaterializationErrorV0, LinkedEmissionMaterializationErrorV0,
21    LinkedEmissionModuleRegionV0, LinkedEmissionOrderEntryRegionV0, LinkedStylesheetV0,
22    LinkedStylesheetWithEmissionItemsV0, TransformBundleAssetUrlRewriteSummaryV0,
23    TransformBundleDependencyResolutionV0, TransformBundleEdgeKind,
24    TransformBundleEmissionAdmissionV0, TransformBundleEmissionItemProjectionV0,
25    TransformBundleInstanceReachabilityInputV0, TransformBundleLinkErrorV0,
26    TransformBundleLinkOptionsV0, TransformBundleLinkProjectionSetV0,
27    TransformBundleLinkerProjectionV0, TransformBundleModuleInputV0,
28    TransformBundleParsedModuleInputV0, TransformBundleResolvedDependencyV0,
29    TransformBundleSemanticReachabilityInputV0, TransformBundleSourceSummaryV0,
30    TransformBundleTransformedModuleV0, bundle_edge_is_module_dependency,
31    evaluate_omena_transform_bundle_projection_emission_admission_with_resolved_dependencies_and_options,
32    link_legacy_path_inferred_bundle, link_omena_transform_bundle_modules,
33    link_omena_transform_bundle_modules_with_options,
34    link_omena_transform_bundle_modules_with_semantic_reachability,
35    link_omena_transform_bundle_modules_with_semantic_reachability_and_metadata,
36    link_omena_transform_bundle_projection_with_emission_items_and_resolved_dependencies_and_options,
37    link_omena_transform_bundle_projection_with_resolved_dependencies_and_options,
38    link_resolved_bundle, materialize_omena_transform_bundle_linked_stylesheet,
39    materialize_omena_transform_bundle_linked_stylesheet_with_emission_items,
40    normalize_omena_transform_bundle_path,
41    project_omena_transform_bundle_linker_and_emission_items,
42    project_omena_transform_bundle_linker_and_emission_items_from_parsed_modules,
43    project_omena_transform_bundle_linker_and_emission_items_from_parsed_modules_with_instance_reachability,
44    project_omena_transform_bundle_linker_inputs,
45    project_omena_transform_bundle_linker_inputs_from_parsed_modules,
46    rewrite_omena_transform_bundle_asset_urls_in_source,
47    summarize_omena_transform_bundle_from_source,
48};
49pub use omena_transform_cst::{
50    MinifyPassClassificationV0, MinifyPassProfileClassV0,
51    NATIVE_CSS_STATIC_EVAL_DIALECT_RESTRICTION_V0, NATIVE_CSS_STATIC_EVAL_OPT_IN_POLICY_V0,
52    NATIVE_CSS_STATIC_EVAL_SPEC_SNAPSHOT_V0, STRICT_VERIFICATION_BUILD_PROFILE_ID_V0,
53    TRANSFORM_PASS_CATALOG_LEN, TransformBuildProfileV0, TransformPassKind,
54    TransformStrictPolicyDescriptorV0, all_transform_pass_kinds, closed_world_minify_build_profile,
55    default_minify_build_profiles, default_minify_pass_classifications, safe_minify_build_profile,
56    semantic_minify_build_profile, strict_policy_descriptor_for_profile,
57    strict_verification_build_profile, transform_pass_requires_closed_world_bundle,
58    transform_pass_sort_ordinal, with_transform_pass_sort_ordinal_overrides_for_test,
59};
60pub use omena_transform_egg::{
61    EggRewriteSourceWitnessV0, TransformEggPlanV0, execute_egg_rewrite_witnesses_for_css_source,
62    plan_egg_rewrite_passes_for_source,
63};
64pub use omena_transform_passes::{
65    CssModuleTokenCollisionPathScopeV0, CssModuleTokenCollisionV0,
66    CssModuleTokenInterfaceMismatchV0, CssModuleTokenOwnershipCensusV0, CssModuleTokenOwnershipV0,
67    CustomPropertyLeastFixedPointSummaryV0, ExternalCssSemanticChangeClassificationV0,
68    ExternalCssSemanticChangeKindV0, ExternalCssSemanticChangeV0, ExternalCssSemanticDiffV0,
69    ExternalCssSemanticEntryV0, RollbackReceiptV0, RollbackScopeV0,
70    TransformCascadeEnvironmentDeclarationV0, TransformCascadeEnvironmentV0,
71    TransformClassNameRewriteV0, TransformCssModuleComposesResolutionV0,
72    TransformCssModuleValueResolutionV0, TransformDecision, TransformDesignTokenRouteV0,
73    TransformExecutionContextV0, TransformExecutionPolicyV0, TransformExecutionSummaryV0,
74    TransformImportInlineV0, TransformLessInlineLiteralPlaceholderV0,
75    TransformModuleCssModuleContextV0, TransformModuleEvaluationNativeEditV0,
76    TransformModuleEvaluationNativeReplacementV0, TransformModuleEvaluationOracleV0,
77    TransformModuleEvaluationV0, TransformModuleQualifiedExecutionErrorV0,
78    TransformModuleQualifiedShakeSummaryV0, TransformPassExecutionOutcomeV0, TransformPassPlanV0,
79    TransformSemanticGuaranteeTierV0, TransformSemanticPreservationDecisionV0,
80    TransformStrictPolicyEventV0, TransformStrictPolicyReasonV0, TransformStrictPolicySummaryV0,
81    TransformVendorPrefixPolicyV0, TransformWinnerEqualityAbsenceReasonV0,
82    TransformWinnerEqualityAbsenceV0, TransformWinnerEqualityAxisV0,
83    classify_transform_reachability_precision, compare_external_css_semantic_changes_v0,
84    compare_transform_css_semantics_v0,
85    execute_transform_passes_on_module_with_dialect_context_and_closed_world_bundle,
86    execute_transform_passes_on_module_with_dialect_context_policy_and_closed_world_bundle,
87    execute_transform_passes_on_module_with_dialect_context_policy_and_closed_world_bundle_and_retained_class_names,
88    execute_transform_passes_on_source_with_dialect_and_context,
89    execute_transform_passes_on_source_with_dialect_context_and_closed_world_bundle,
90    execute_transform_passes_on_source_with_dialect_context_and_policy,
91    execute_transform_passes_on_source_with_dialect_context_closed_world_bundle_and_precision,
92    execute_transform_passes_on_source_with_dialect_context_closed_world_bundle_precision_and_policy,
93    expand_css_nested_selector, external_css_semantic_diff_is_total_v0, inline_css_imports,
94    inline_css_imports_for_static_module_evaluation, parse_static_css_cascade_value,
95    plan_transform_passes, reduce_static_numeric_expression,
96    resolve_static_css_modules_local_value_resolutions_from_source,
97    restore_less_inline_literal_placeholders,
98    summarize_static_css_custom_property_fixed_point_from_source,
99};
100/// Compatibility aliases for the superseded trace name.
101/// Owner: `omena-query-transform-runner` maintainers. Removal condition: not
102/// before 1.0, after downstream migration and zero audited non-compat uses.
103#[cfg(feature = "transform-catalog-trace")]
104#[allow(deprecated)]
105#[deprecated(
106    since = "0.4.0",
107    note = "use the TransformCatalog trace surface; removal is not before 1.0 and requires downstream migration plus zero audited non-compatibility uses"
108)]
109pub use omena_transform_passes::{
110    LawvereDifferentialCommutativityWitnessV0, LawvereModelTraceV0, TransformPassParallelPlanV0,
111    evaluate_lawvere_reorderability_with_differential_corpus,
112    execute_transform_passes_on_source_with_lawvere_trace_and_dialect,
113    plan_transform_passes_parallel_lawvere_layers,
114};
115#[cfg(feature = "transform-catalog-trace")]
116pub use omena_transform_passes::{
117    ReorderabilityCertificateV0, TransformCatalogDifferentialCommutativityWitnessV0,
118    TransformCatalogModelTraceV0, TransformCatalogTransformPassParallelPlanV0,
119    evaluate_transform_catalog_reorderability_with_differential_corpus,
120    execute_transform_passes_on_source_with_transform_catalog_trace_and_dialect,
121    plan_transform_passes_parallel_transform_catalog_layers,
122};
123pub use omena_transform_print::{
124    PrettyFormatOptionsV0, StyleDialect, TransformPrintArtifactV0, TransformPrintMode,
125    TransformPrintOptionsV0, TransformSourceMapCompositionV0, TransformSourceMapPointV0,
126    TransformSourceMapSegmentV0, TransformSourceMapV3V0,
127    compose_transform_source_map_v3_with_upstream_map, default_print_options,
128    print_transform_cst_source_with_dialect_and_pretty_options,
129    print_transform_execution_artifact_with_dialect_and_source, serialize_transform_source_map_v3,
130    serialize_transform_source_map_v3_with_source_contents, transform_source_map_point,
131};
132pub use omena_transform_target::{
133    TargetFeatureSupportV0, TargetTransformOptionsV0, TransformTargetPlanV0,
134    TransformTargetQueryPlanV0, conservative_target_options, modern_feature_support,
135    plan_target_transforms, plan_target_transforms_from_query,
136};
137
138pub const OMENA_QUERY_TRANSFORM_RUNNER_COLLAPSED_CRATES_V0: [&str; 6] = [
139    "omena-bundler",
140    "omena-transform-cst",
141    "omena-transform-egg",
142    "omena-transform-passes",
143    "omena-transform-print",
144    "omena-transform-target",
145];
146
147pub fn materialize_transform_module_evaluation_native_edits(
148    input_css: &str,
149    native_edits: &[TransformModuleEvaluationNativeEditV0],
150) -> Option<String> {
151    if native_edits.is_empty() {
152        return None;
153    }
154
155    let mut edits = native_edits.to_vec();
156    edits.sort_by_key(|edit| edit.start);
157
158    let mut previous_end = 0usize;
159    for edit in &edits {
160        if edit.start < previous_end
161            || edit.start > edit.end
162            || edit.end > input_css.len()
163            || !input_css.is_char_boundary(edit.start)
164            || !input_css.is_char_boundary(edit.end)
165        {
166            return None;
167        }
168        previous_end = edit.end;
169    }
170
171    let mut output = input_css.to_string();
172    for edit in edits.iter().rev() {
173        output.replace_range(edit.start..edit.end, edit.replacement.as_str());
174    }
175    Some(output)
176}
177
178#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
179#[serde(rename_all = "camelCase")]
180pub struct OmenaQueryTransformRunnerBoundaryV0 {
181    pub schema_version: &'static str,
182    pub product: &'static str,
183    pub boundary_kind: &'static str,
184    pub collapsed_transform_crate_count: usize,
185    pub collapsed_transform_crates: Vec<&'static str>,
186    pub direct_query_dependency_replacement: &'static str,
187    pub ready_surfaces: Vec<&'static str>,
188}
189
190pub fn summarize_omena_query_transform_runner_boundary_with_transform_catalog_v0()
191-> OmenaQueryTransformRunnerBoundaryV0 {
192    let ready_surfaces = vec![
193        "transformPlannerBoundary",
194        "transformExecutorBoundary",
195        "transformPrinterBoundary",
196        "transformSourceMapV3SerializerBoundary",
197        "transformTargetPlannerBoundary",
198        "transformEggWitnessBoundary",
199    ];
200    #[cfg(feature = "transform-catalog-trace")]
201    let mut ready_surfaces = ready_surfaces;
202    #[cfg(feature = "transform-catalog-trace")]
203    ready_surfaces.push("transformCatalogTraceBoundary");
204
205    OmenaQueryTransformRunnerBoundaryV0 {
206        schema_version: "0",
207        product: "omena-query-transform-runner.boundary",
208        boundary_kind: "query-transform-runner-split",
209        collapsed_transform_crate_count: OMENA_QUERY_TRANSFORM_RUNNER_COLLAPSED_CRATES_V0.len(),
210        collapsed_transform_crates: OMENA_QUERY_TRANSFORM_RUNNER_COLLAPSED_CRATES_V0.to_vec(),
211        direct_query_dependency_replacement: "omena-query-transform-runner",
212        ready_surfaces,
213    }
214}
215
216#[deprecated(
217    since = "0.4.0",
218    note = "use summarize_omena_query_transform_runner_boundary_with_transform_catalog_v0; removal is not before 1.0 and requires downstream migration plus zero audited non-compatibility uses"
219)]
220pub fn summarize_omena_query_transform_runner_boundary_v0() -> OmenaQueryTransformRunnerBoundaryV0 {
221    #[cfg(feature = "transform-catalog-trace")]
222    let mut summary = summarize_omena_query_transform_runner_boundary_with_transform_catalog_v0();
223    #[cfg(not(feature = "transform-catalog-trace"))]
224    let summary = summarize_omena_query_transform_runner_boundary_with_transform_catalog_v0();
225    #[cfg(feature = "transform-catalog-trace")]
226    if let Some(surface) = summary
227        .ready_surfaces
228        .iter_mut()
229        .find(|surface| **surface == "transformCatalogTraceBoundary")
230    {
231        *surface = "transformLawvereTraceBoundary";
232    }
233    summary
234}
235
236#[cfg(test)]
237mod tests {
238    use super::*;
239
240    /// Exact pre-1.0 transform-runner boundary projection retained for wire
241    /// compatibility. Owner: `omena-query-transform-runner` maintainers.
242    /// Removal is not before 1.0 and requires downstream migration plus zero
243    /// audited non-compatibility uses.
244    #[cfg(feature = "transform-catalog-trace")]
245    #[deprecated(
246        since = "0.4.0",
247        note = "compatibility projection; removal is not before 1.0 and requires downstream migration plus zero audited non-compatibility uses"
248    )]
249    const COMPATIBILITY_TRANSFORM_RUNNER_BOUNDARY_JSON_V0: &str = r#"{"schemaVersion":"0","product":"omena-query-transform-runner.boundary","boundaryKind":"query-transform-runner-split","collapsedTransformCrateCount":6,"collapsedTransformCrates":["omena-bundler","omena-transform-cst","omena-transform-egg","omena-transform-passes","omena-transform-print","omena-transform-target"],"directQueryDependencyReplacement":"omena-query-transform-runner","readySurfaces":["transformPlannerBoundary","transformExecutorBoundary","transformPrinterBoundary","transformSourceMapV3SerializerBoundary","transformTargetPlannerBoundary","transformEggWitnessBoundary","transformLawvereTraceBoundary"]}"#;
250
251    #[test]
252    fn transform_runner_boundary_collapses_transform_family_for_query() {
253        let summary = summarize_omena_query_transform_runner_boundary_with_transform_catalog_v0();
254
255        assert_eq!(summary.collapsed_transform_crate_count, 6);
256        assert_eq!(
257            summary.collapsed_transform_crates,
258            OMENA_QUERY_TRANSFORM_RUNNER_COLLAPSED_CRATES_V0
259        );
260        assert!(
261            summary
262                .ready_surfaces
263                .contains(&"transformExecutorBoundary")
264        );
265        assert!(
266            summary
267                .ready_surfaces
268                .contains(&"transformTargetPlannerBoundary")
269        );
270    }
271
272    #[cfg(feature = "transform-catalog-trace")]
273    #[test]
274    #[allow(deprecated)]
275    fn transform_runner_boundary_preserves_legacy_and_canonical_serialized_projections()
276    -> Result<(), serde_json::Error> {
277        let legacy = serde_json::to_string(&summarize_omena_query_transform_runner_boundary_v0())?;
278        let canonical = serde_json::to_string(
279            &summarize_omena_query_transform_runner_boundary_with_transform_catalog_v0(),
280        )?;
281
282        assert_eq!(legacy, COMPATIBILITY_TRANSFORM_RUNNER_BOUNDARY_JSON_V0);
283        assert_eq!(
284            canonical,
285            r#"{"schemaVersion":"0","product":"omena-query-transform-runner.boundary","boundaryKind":"query-transform-runner-split","collapsedTransformCrateCount":6,"collapsedTransformCrates":["omena-bundler","omena-transform-cst","omena-transform-egg","omena-transform-passes","omena-transform-print","omena-transform-target"],"directQueryDependencyReplacement":"omena-query-transform-runner","readySurfaces":["transformPlannerBoundary","transformExecutorBoundary","transformPrinterBoundary","transformSourceMapV3SerializerBoundary","transformTargetPlannerBoundary","transformEggWitnessBoundary","transformCatalogTraceBoundary"]}"#
286        );
287
288        Ok(())
289    }
290
291    #[test]
292    fn transform_runner_materializes_sorted_native_edits() {
293        let input_css = ".button { color: red; margin: 1px; }";
294        let color_start = input_css.find("red").unwrap_or(input_css.len());
295        let margin_start = input_css.find("1px").unwrap_or(input_css.len());
296
297        let output = materialize_transform_module_evaluation_native_edits(
298            input_css,
299            &[
300                TransformModuleEvaluationNativeEditV0 {
301                    start: margin_start,
302                    end: margin_start + "1px".len(),
303                    replacement: "2px".to_string(),
304                    edit_kind: "value".to_string(),
305                    abstract_value: None,
306                    abstract_value_kind: None,
307                },
308                TransformModuleEvaluationNativeEditV0 {
309                    start: color_start,
310                    end: color_start + "red".len(),
311                    replacement: "blue".to_string(),
312                    edit_kind: "value".to_string(),
313                    abstract_value: None,
314                    abstract_value_kind: None,
315                },
316            ],
317        );
318
319        assert_eq!(
320            output.as_deref(),
321            Some(".button { color: blue; margin: 2px; }")
322        );
323    }
324
325    #[test]
326    fn transform_runner_rejects_overlapping_native_edits() {
327        let output = materialize_transform_module_evaluation_native_edits(
328            "abcdef",
329            &[
330                TransformModuleEvaluationNativeEditV0 {
331                    start: 1,
332                    end: 4,
333                    replacement: "x".to_string(),
334                    edit_kind: "value".to_string(),
335                    abstract_value: None,
336                    abstract_value_kind: None,
337                },
338                TransformModuleEvaluationNativeEditV0 {
339                    start: 3,
340                    end: 5,
341                    replacement: "y".to_string(),
342                    edit_kind: "value".to_string(),
343                    abstract_value: None,
344                    abstract_value_kind: None,
345                },
346            ],
347        );
348
349        assert_eq!(output, None);
350    }
351}