use super::*;
use super::parser_facade::parse_omena_query_omena_parser_style_source;
mod context;
mod css_modules;
mod design_tokens;
mod imports;
mod static_stylesheet;
use context::{
find_target_style_source, merge_target_options_transform_context, merge_transform_context,
};
use css_modules::{
derive_class_name_rewrites_for_transform_context,
derive_css_module_composes_resolutions_for_transform_context,
derive_css_module_value_resolutions_for_transform_context,
};
use design_tokens::derive_design_token_routes_for_transform_context;
use imports::derive_import_inlines_for_transform_context;
use static_stylesheet::{
derive_static_scss_module_use_evaluations_for_transform_context,
derive_static_stylesheet_module_evaluation_for_transform_context,
};
pub fn summarize_omena_query_transform_plan_from_source(
style_path: &str,
style_source: &str,
target_label: &str,
target_support: OmenaQueryTargetFeatureSupportV0,
target_options: OmenaQueryTargetTransformOptionsV0,
print_options: OmenaQueryTransformPrintOptionsV0,
) -> OmenaQueryTransformPlanSummaryV0 {
summarize_omena_query_transform_plan_from_source_with_context(
style_path,
style_source,
target_label,
target_support,
target_options,
print_options,
&TransformExecutionContextV0::default(),
)
}
pub fn summarize_omena_query_transform_plan_from_source_with_context(
style_path: &str,
style_source: &str,
target_label: &str,
target_support: OmenaQueryTargetFeatureSupportV0,
target_options: OmenaQueryTargetTransformOptionsV0,
print_options: OmenaQueryTransformPrintOptionsV0,
context: &TransformExecutionContextV0,
) -> OmenaQueryTransformPlanSummaryV0 {
let dialect = omena_parser_dialect_for_style_path(style_path);
let bundle = summarize_omena_transform_bundle_from_source(style_path, style_source, dialect);
let target = plan_target_transforms(target_label, target_support, target_options);
let execution_context = merge_target_options_transform_context(context, target_options);
summarize_omena_query_transform_plan_from_parts(TransformPlanPartsV0 {
style_path,
style_source,
dialect,
bundle,
target,
target_query: None,
print_options,
context: &execution_context,
})
}
pub fn summarize_omena_query_transform_plan_from_target_query(
style_path: &str,
style_source: &str,
target_query: &str,
target_options: OmenaQueryTargetTransformOptionsV0,
print_options: OmenaQueryTransformPrintOptionsV0,
) -> OmenaQueryTransformPlanSummaryV0 {
summarize_omena_query_transform_plan_from_target_query_with_context(
style_path,
style_source,
target_query,
target_options,
print_options,
&TransformExecutionContextV0::default(),
)
}
pub fn summarize_omena_query_transform_plan_from_target_query_with_context(
style_path: &str,
style_source: &str,
target_query: &str,
target_options: OmenaQueryTargetTransformOptionsV0,
print_options: OmenaQueryTransformPrintOptionsV0,
context: &TransformExecutionContextV0,
) -> OmenaQueryTransformPlanSummaryV0 {
let dialect = omena_parser_dialect_for_style_path(style_path);
let bundle = summarize_omena_transform_bundle_from_source(style_path, style_source, dialect);
let target_query_plan = plan_target_transforms_from_query(target_query, target_options);
let target = target_query_plan.transform_plan.clone();
let execution_context = merge_target_options_transform_context(context, target_options);
summarize_omena_query_transform_plan_from_parts(TransformPlanPartsV0 {
style_path,
style_source,
dialect,
bundle,
target,
target_query: Some(target_query_plan),
print_options,
context: &execution_context,
})
}
struct TransformPlanPartsV0<'a> {
style_path: &'a str,
style_source: &'a str,
dialect: OmenaParserStyleDialect,
bundle: TransformBundleSourceSummaryV0,
target: TransformTargetPlanV0,
target_query: Option<OmenaQueryTransformTargetQueryPlanV0>,
print_options: OmenaQueryTransformPrintOptionsV0,
context: &'a TransformExecutionContextV0,
}
fn summarize_omena_query_transform_plan_from_parts(
parts: TransformPlanPartsV0<'_>,
) -> OmenaQueryTransformPlanSummaryV0 {
let egg = plan_egg_rewrite_passes_for_source(parts.style_source);
let custom_property_fixed_point = summarize_static_css_custom_property_fixed_point_from_source(
parts.style_source,
parts.dialect,
);
let mut combined_passes = Vec::new();
extend_passes_from_ids(&parts.bundle.planned_pass_ids, &mut combined_passes);
extend_passes_from_ids(&parts.target.planned_pass_ids, &mut combined_passes);
extend_passes_from_ids(&egg.planned_pass_ids, &mut combined_passes);
combined_passes.push(TransformPassKind::PrintCss);
combined_passes.sort_by_key(|pass| pass.ordinal());
combined_passes.dedup();
let combined_plan = plan_transform_passes(&combined_passes);
let semantic_signature = format!(
"omena-query-transform:{}:{}",
parts.style_path,
parts.style_source.len()
);
let execution = execute_transform_passes_on_source_with_dialect_and_context(
parts.style_source,
parts.dialect,
&combined_passes,
parts.context,
);
let print = print_transform_execution_artifact_with_dialect_and_source(
parts.style_path,
parts.style_source,
parts.dialect,
semantic_signature,
&combined_passes,
parts.print_options,
&execution,
);
let egg_witnesses = execute_egg_rewrite_witnesses_for_css_source(
parts.style_source,
&execution.output_css,
&egg.planned_pass_ids,
);
let semantic_removal_count = execution.semantic_removals.len();
let combined_pass_ids = combined_plan.ordered_pass_ids.clone();
let combined_violated_dag_edge_count = combined_plan.violated_dag_edge_count;
OmenaQueryTransformPlanSummaryV0 {
schema_version: "0",
product: "omena-query.transform-plan",
style_path: parts.style_path.to_string(),
dialect: omena_parser_style_dialect_label(parts.dialect),
bundle: parts.bundle,
target: parts.target,
target_query: parts.target_query,
egg,
egg_witnesses,
custom_property_fixed_point,
print,
execution,
semantic_removal_count,
combined_plan,
combined_pass_ids,
combined_violated_dag_edge_count,
ready_surfaces: vec![
"transformBundlePlan",
"transformTargetPlan",
"transformEggPlan",
"transformEggExecutionWitnesses",
"customPropertyLeastFixedPoint",
"transformPrintArtifact",
"transformExecutionRuntime",
"cascadeProofObligations",
"combinedTransformPassPlan",
],
}
}
pub fn execute_omena_query_transform_passes_from_source(
style_path: &str,
style_source: &str,
requested_pass_ids: &[String],
) -> OmenaQueryTransformExecuteSummaryV0 {
execute_omena_query_transform_passes_from_source_with_context(
style_path,
style_source,
requested_pass_ids,
&TransformExecutionContextV0::default(),
)
}
pub fn summarize_omena_query_consumer_check_style_source(
style_path: &str,
style_source: &str,
) -> OmenaQueryConsumerCheckSummaryV0 {
let dialect = omena_parser_dialect_for_style_path(style_path);
let parse_result = parse_omena_query_omena_parser_style_source(style_source, dialect);
let style_facts = summarize_omena_query_omena_parser_style_facts(style_source, dialect);
OmenaQueryConsumerCheckSummaryV0 {
schema_version: "0",
product: "omena-query.consumer-check-style-source",
style_path: style_path.to_string(),
dialect: omena_parser_style_dialect_label(dialect),
token_count: parse_result.token_count(),
parser_error_count: parse_result.errors().len(),
class_selector_count: style_facts.class_selector_names.len(),
custom_property_count: style_facts.custom_property_names.len(),
keyframe_count: style_facts.keyframe_names.len(),
ready_surfaces: vec![
"consumerCheckFacade",
"parserFactSummary",
"styleDocumentDiagnostics",
],
}
}
pub fn execute_omena_query_consumer_build_style_source(
style_path: &str,
style_source: &str,
requested_pass_ids: &[String],
) -> OmenaQueryConsumerBuildSummaryV0 {
execute_omena_query_consumer_build_style_source_with_context(
style_path,
style_source,
requested_pass_ids,
&TransformExecutionContextV0::default(),
)
}
pub fn execute_omena_query_consumer_build_style_source_with_context(
style_path: &str,
style_source: &str,
requested_pass_ids: &[String],
context: &TransformExecutionContextV0,
) -> OmenaQueryConsumerBuildSummaryV0 {
let pass_ids = if requested_pass_ids.is_empty() {
all_transform_pass_kinds()
.into_iter()
.map(|pass| pass.id().to_string())
.collect::<Vec<_>>()
} else {
requested_pass_ids.to_vec()
};
let context = merge_single_source_transform_context(style_path, style_source, context);
let execution_summary = execute_omena_query_transform_passes_from_source_with_context(
style_path,
style_source,
&pass_ids,
&context,
);
OmenaQueryConsumerBuildSummaryV0 {
schema_version: "0",
product: "omena-query.consumer-build-style-source",
style_path: style_path.to_string(),
dialect: omena_parser_style_dialect_label(omena_parser_dialect_for_style_path(style_path)),
requested_pass_ids: requested_pass_ids.to_vec(),
target_query: None,
unknown_pass_ids: execution_summary.unknown_pass_ids,
semantic_removal_count: execution_summary.semantic_removal_count,
execution: execution_summary.execution,
ready_surfaces: vec![
"consumerBuildFacade",
"singleSourceTransformContextProducer",
"transformExecutionRuntime",
"transformPassOutcomeContract",
],
}
}
pub fn execute_omena_query_consumer_build_style_source_with_engine_input_context(
style_path: &str,
style_source: &str,
requested_pass_ids: &[String],
input: &EngineInputV2,
closed_style_world: bool,
) -> OmenaQueryConsumerBuildSummaryV0 {
let context_summary = summarize_omena_query_transform_context_from_engine_input(
input,
style_path,
closed_style_world,
);
let mut summary = execute_omena_query_consumer_build_style_source_with_context(
style_path,
style_source,
requested_pass_ids,
&context_summary.context,
);
summary
.ready_surfaces
.push("semanticReachabilityTransformContext");
summary
.ready_surfaces
.push("expressionDomainSelectorProjection");
summary
}
pub fn execute_omena_query_consumer_build_style_sources_with_context(
target_style_path: &str,
style_sources: &[OmenaQueryStyleSourceInputV0],
requested_pass_ids: &[String],
context: &TransformExecutionContextV0,
package_manifests: &[OmenaQueryStylePackageManifestV0],
) -> Result<OmenaQueryConsumerBuildSummaryV0, String> {
let Some(target_source) = find_target_style_source(target_style_path, style_sources) else {
return Err(format!(
"target style path {target_style_path:?} was not found in workspace style sources"
));
};
let context = merge_workspace_transform_context(
target_style_path,
style_sources,
context,
package_manifests,
);
let mut summary = execute_omena_query_consumer_build_style_source_with_context(
target_style_path,
target_source,
requested_pass_ids,
&context,
);
summary
.ready_surfaces
.push("multiSourceTransformContextProducer");
Ok(summary)
}
pub fn execute_omena_query_consumer_build_style_sources(
target_style_path: &str,
style_sources: &[OmenaQueryStyleSourceInputV0],
requested_pass_ids: &[String],
package_manifests: &[OmenaQueryStylePackageManifestV0],
) -> Result<OmenaQueryConsumerBuildSummaryV0, String> {
execute_omena_query_consumer_build_style_sources_with_context(
target_style_path,
style_sources,
requested_pass_ids,
&TransformExecutionContextV0::default(),
package_manifests,
)
}
pub fn execute_omena_query_consumer_build_style_source_for_target_query(
style_path: &str,
style_source: &str,
target_query: &str,
) -> OmenaQueryConsumerBuildSummaryV0 {
execute_omena_query_consumer_build_style_source_for_target_query_with_options(
style_path,
style_source,
target_query,
conservative_omena_query_target_options(),
)
}
pub fn execute_omena_query_consumer_build_style_source_for_target_query_with_options(
style_path: &str,
style_source: &str,
target_query: &str,
target_options: OmenaQueryTargetTransformOptionsV0,
) -> OmenaQueryConsumerBuildSummaryV0 {
execute_omena_query_consumer_build_style_source_for_target_query_with_context_and_options(
style_path,
style_source,
target_query,
&TransformExecutionContextV0::default(),
target_options,
)
}
pub fn execute_omena_query_consumer_build_style_source_for_target_query_with_context_and_options(
style_path: &str,
style_source: &str,
target_query: &str,
context: &TransformExecutionContextV0,
target_options: OmenaQueryTargetTransformOptionsV0,
) -> OmenaQueryConsumerBuildSummaryV0 {
let context = merge_single_source_transform_context(style_path, style_source, context);
let plan = summarize_omena_query_transform_plan_from_target_query_with_context(
style_path,
style_source,
target_query,
target_options,
default_omena_query_transform_print_options(),
&context,
);
let requested_pass_ids = plan
.combined_pass_ids
.iter()
.map(|pass_id| (*pass_id).to_string())
.collect::<Vec<_>>();
OmenaQueryConsumerBuildSummaryV0 {
schema_version: "0",
product: "omena-query.consumer-build-style-source",
style_path: plan.style_path,
dialect: plan.dialect,
requested_pass_ids,
target_query: plan.target_query,
unknown_pass_ids: Vec::new(),
semantic_removal_count: plan.semantic_removal_count,
execution: plan.execution,
ready_surfaces: vec![
"consumerBuildFacade",
"targetQueryBuildFacade",
"singleSourceTransformContextProducer",
"transformExecutionRuntime",
"transformPassOutcomeContract",
],
}
}
pub fn execute_omena_query_consumer_build_style_sources_for_target_query_with_context_and_options(
target_style_path: &str,
style_sources: &[OmenaQueryStyleSourceInputV0],
target_query: &str,
context: &TransformExecutionContextV0,
target_options: OmenaQueryTargetTransformOptionsV0,
package_manifests: &[OmenaQueryStylePackageManifestV0],
) -> Result<OmenaQueryConsumerBuildSummaryV0, String> {
let Some(target_source) = find_target_style_source(target_style_path, style_sources) else {
return Err(format!(
"target style path {target_style_path:?} was not found in workspace style sources"
));
};
let context = merge_workspace_transform_context(
target_style_path,
style_sources,
context,
package_manifests,
);
let mut summary =
execute_omena_query_consumer_build_style_source_for_target_query_with_context_and_options(
target_style_path,
target_source,
target_query,
&context,
target_options,
);
summary
.ready_surfaces
.push("multiSourceTransformContextProducer");
Ok(summary)
}
pub fn execute_omena_query_consumer_build_style_sources_for_target_query_with_options(
target_style_path: &str,
style_sources: &[OmenaQueryStyleSourceInputV0],
target_query: &str,
target_options: OmenaQueryTargetTransformOptionsV0,
package_manifests: &[OmenaQueryStylePackageManifestV0],
) -> Result<OmenaQueryConsumerBuildSummaryV0, String> {
execute_omena_query_consumer_build_style_sources_for_target_query_with_context_and_options(
target_style_path,
style_sources,
target_query,
&TransformExecutionContextV0::default(),
target_options,
package_manifests,
)
}
fn derive_single_source_transform_context(
style_path: &str,
style_source: &str,
) -> TransformExecutionContextV0 {
summarize_omena_query_transform_context_from_sources(
style_path,
[(style_path, style_source)],
&[],
)
.context
}
fn merge_single_source_transform_context(
style_path: &str,
style_source: &str,
context: &TransformExecutionContextV0,
) -> TransformExecutionContextV0 {
merge_transform_context(
derive_single_source_transform_context(style_path, style_source),
context,
)
}
fn merge_workspace_transform_context(
target_style_path: &str,
style_sources: &[OmenaQueryStyleSourceInputV0],
context: &TransformExecutionContextV0,
package_manifests: &[OmenaQueryStylePackageManifestV0],
) -> TransformExecutionContextV0 {
let style_refs = style_sources
.iter()
.map(|source| (source.style_path.as_str(), source.style_source.as_str()))
.collect::<Vec<_>>();
let derived = summarize_omena_query_transform_context_from_sources(
target_style_path,
style_refs,
package_manifests,
)
.context;
merge_transform_context(derived, context)
}
pub fn summarize_omena_query_transform_context_from_engine_input(
input: &EngineInputV2,
target_style_path: &str,
closed_style_world: bool,
) -> OmenaQueryTransformContextFromEngineInputSummaryV0 {
let projection_summary = summarize_omena_query_expression_domain_selector_projection(input);
let mut reachable_class_names = BTreeSet::new();
let mut reachability_sources = Vec::new();
for projection in &projection_summary.projections {
if projection.target_style_paths.is_empty()
|| projection
.target_style_paths
.iter()
.any(|path| path == target_style_path)
{
reachable_class_names.extend(projection.selector_names.iter().cloned());
reachability_sources.push(OmenaQuerySemanticReachabilitySourceV0 {
graph_id: projection.graph_id.clone(),
file_path: projection.file_path.clone(),
node_id: projection.node_id.clone(),
target_style_paths: projection.target_style_paths.clone(),
value_kind: projection.value_kind,
reduced_product: projection.reduced_product.clone(),
selector_names: projection.selector_names.clone(),
certainty: projection.certainty,
});
}
}
let semantic_context = TransformExecutionContextV0 {
closed_style_world,
reachable_class_names: reachable_class_names.into_iter().collect(),
..TransformExecutionContextV0::default()
};
let style_sources = input
.styles
.iter()
.filter_map(|style| {
style
.source
.as_deref()
.map(|source| (style.file_path.as_str(), source))
})
.collect::<Vec<_>>();
let source_context_summary = (!style_sources.is_empty()).then(|| {
summarize_omena_query_transform_context_from_sources(target_style_path, style_sources, &[])
});
let context = if let Some(source_context_summary) = &source_context_summary {
merge_transform_context(source_context_summary.context.clone(), &semantic_context)
} else {
semantic_context
};
let mut ready_surfaces = vec![
"expressionDomainSelectorProjection",
"semanticReachabilityTransformContext",
];
if source_context_summary.is_some() {
ready_surfaces.push("engineInputStyleSourceTransformContext");
}
OmenaQueryTransformContextFromEngineInputSummaryV0 {
schema_version: "0",
product: "omena-query.transform-context-from-engine-input",
input_version: input.version.clone(),
target_style_path: target_style_path.to_string(),
closed_style_world,
style_source_count: source_context_summary
.as_ref()
.map_or(0, |summary| summary.style_count),
projection_count: projection_summary.projection_count,
selected_projection_count: reachability_sources.len(),
import_inline_count: context.import_inlines.len(),
class_name_rewrite_count: context.class_name_rewrites.len(),
css_module_composes_resolution_count: context.css_module_composes_resolutions.len(),
css_module_value_resolution_count: context.css_module_value_resolutions.len(),
design_token_route_count: context.design_token_routes.len(),
reachable_class_name_count: context.reachable_class_names.len(),
reachable_keyframe_name_count: context.reachable_keyframe_names.len(),
reachable_value_name_count: context.reachable_value_names.len(),
reachable_custom_property_name_count: context.reachable_custom_property_names.len(),
reachability_sources,
context,
ready_surfaces,
}
}
pub fn list_omena_query_transform_pass_summaries() -> Vec<OmenaQueryTransformPassSummaryV0> {
all_transform_pass_kinds()
.into_iter()
.map(|kind| OmenaQueryTransformPassSummaryV0 {
id: kind.id(),
title: kind.title(),
reads_semantic_graph: kind.reads_semantic_graph(),
reads_cascade_model: kind.reads_cascade_model(),
})
.collect()
}
pub fn execute_omena_query_transform_passes_from_source_with_context(
style_path: &str,
style_source: &str,
requested_pass_ids: &[String],
context: &TransformExecutionContextV0,
) -> OmenaQueryTransformExecuteSummaryV0 {
let mut requested_passes = Vec::new();
let mut unknown_pass_ids = Vec::new();
for pass_id in requested_pass_ids {
match transform_pass_kind_from_id(pass_id) {
Some(pass) => requested_passes.push(pass),
None => unknown_pass_ids.push(pass_id.clone()),
}
}
let dialect = omena_parser_dialect_for_style_path(style_path);
let execution = execute_transform_passes_on_source_with_dialect_and_context(
style_source,
dialect,
&requested_passes,
context,
);
let semantic_removal_count = execution.semantic_removals.len();
OmenaQueryTransformExecuteSummaryV0 {
schema_version: "0",
product: "omena-query.transform-execute",
style_path: style_path.to_string(),
requested_pass_ids: requested_pass_ids.to_vec(),
unknown_pass_ids,
execution,
semantic_removal_count,
ready_surfaces: vec!["transformExecutionRuntime", "transformPassOutcomeContract"],
}
}
pub fn summarize_omena_query_transform_context_from_sources<'a>(
target_style_path: &str,
styles: impl IntoIterator<Item = (&'a str, &'a str)>,
package_manifests: &[OmenaQueryStylePackageManifestV0],
) -> OmenaQueryTransformContextFromSourcesSummaryV0 {
let style_sources = styles.into_iter().collect::<Vec<_>>();
let style_count = style_sources.len();
let style_fact_entries = collect_omena_query_style_fact_entries(style_sources.as_slice());
let source_by_path = style_sources
.iter()
.map(|(style_path, style_source)| ((*style_path).to_string(), (*style_source).to_string()))
.collect::<BTreeMap<_, _>>();
let available_style_paths = style_fact_entries
.iter()
.map(|entry| entry.style_path.as_str())
.collect::<BTreeSet<_>>();
let target_entry = style_fact_entries
.iter()
.find(|entry| entry.style_path == target_style_path);
let mut context = TransformExecutionContextV0::default();
if let Some(entry) = target_entry {
context.import_inlines = derive_import_inlines_for_transform_context(
entry,
&style_fact_entries,
&available_style_paths,
&source_by_path,
package_manifests,
);
let scss_module_uses = derive_static_scss_module_use_evaluations_for_transform_context(
entry,
&available_style_paths,
&source_by_path,
package_manifests,
);
match omena_parser_dialect_for_style_path(entry.style_path.as_str()) {
OmenaParserStyleDialect::Scss | OmenaParserStyleDialect::Sass => {
let dialect = omena_parser_dialect_for_style_path(entry.style_path.as_str());
context.scss_module_evaluation =
derive_static_stylesheet_module_evaluation_for_transform_context(
entry.style_source.as_str(),
dialect,
&context.import_inlines,
&scss_module_uses,
);
}
OmenaParserStyleDialect::Less => {
context.less_module_evaluation =
derive_static_stylesheet_module_evaluation_for_transform_context(
entry.style_source.as_str(),
OmenaParserStyleDialect::Less,
&context.import_inlines,
&[],
);
}
OmenaParserStyleDialect::Css => {}
}
context.class_name_rewrites = derive_class_name_rewrites_for_transform_context(entry);
context.css_module_composes_resolutions =
derive_css_module_composes_resolutions_for_transform_context(
entry,
&style_fact_entries,
&available_style_paths,
package_manifests,
);
context.css_module_value_resolutions =
derive_css_module_value_resolutions_for_transform_context(
entry,
&style_fact_entries,
&available_style_paths,
&source_by_path,
package_manifests,
);
context.design_token_routes = derive_design_token_routes_for_transform_context(
entry,
&style_fact_entries,
package_manifests,
);
}
OmenaQueryTransformContextFromSourcesSummaryV0 {
schema_version: "0",
product: "omena-query.transform-context",
target_style_path: target_style_path.to_string(),
style_count,
import_inline_count: context.import_inlines.len(),
class_name_rewrite_count: context.class_name_rewrites.len(),
css_module_composes_resolution_count: context.css_module_composes_resolutions.len(),
css_module_value_resolution_count: context.css_module_value_resolutions.len(),
design_token_route_count: context.design_token_routes.len(),
reachable_class_name_count: context.reachable_class_names.len(),
reachable_keyframe_name_count: context.reachable_keyframe_names.len(),
reachable_value_name_count: context.reachable_value_names.len(),
reachable_custom_property_name_count: context.reachable_custom_property_names.len(),
context,
ready_surfaces: vec![
"transformContextProducer",
"stylesheetModuleEvaluationProducer",
"cssModuleClassRewriteProducer",
"cssModuleComposesResolutionProducer",
"cssModuleValueResolutionProducer",
"designTokenRouteProducer",
"transitiveImportInlineProducer",
],
}
}
fn apply_transform_source_replacements(
source: &str,
mut replacements: Vec<(usize, usize, String)>,
) -> (String, usize) {
if replacements.is_empty() {
return (source.to_string(), 0);
}
replacements.sort_by_key(|replacement| replacement.0);
let mut output = source.to_string();
let mut mutation_count = 0usize;
for (start, end, replacement) in replacements.into_iter().rev() {
if start > end || end > output.len() {
continue;
}
output.replace_range(start..end, replacement.as_str());
mutation_count += 1;
}
(output, mutation_count)
}
fn transform_token_start(token: &omena_parser::LexedToken) -> usize {
let start: u32 = token.range.start().into();
start as usize
}
fn transform_token_end(token: &omena_parser::LexedToken) -> usize {
let end: u32 = token.range.end().into();
end as usize
}
fn extend_passes_from_ids(ids: &[&'static str], passes: &mut Vec<TransformPassKind>) {
for candidate in all_transform_pass_kinds() {
if ids.contains(&candidate.id()) && !passes.contains(&candidate) {
passes.push(candidate);
}
}
}
fn transform_pass_kind_from_id(pass_id: &str) -> Option<TransformPassKind> {
all_transform_pass_kinds()
.into_iter()
.find(|candidate| candidate.id() == pass_id)
}