///|
fn rule_ref(
code : String,
severity : Severity,
format : String,
description : String,
repair_hint : String,
) -> ValidationRuleReference {
{ code, severity, format, description, repair_hint }
}
///|
pub fn validation_rule_references() -> Array[ValidationRuleReference] {
[
rule_ref(
"duplicate_id",
Error,
"GFF3",
"Two features share the same ID",
"Make ID values unique within the document",
),
rule_ref(
"orphan_parent",
Error,
"GFF3",
"A Parent attribute points to a missing feature",
"Add the parent feature or correct the Parent value",
),
rule_ref(
"invalid_phase",
Warning,
"both",
"A CDS phase is not 0, 1, or 2",
"Normalize CDS phase to one of 0, 1, or 2",
),
rule_ref(
"missing_id",
Warning,
"GFF3",
"A container feature lacks ID",
"Add ID for gene and transcript-like features",
),
rule_ref(
"missing_gene_id",
Error,
"GTF",
"A GTF feature lacks gene_id",
"Add gene_id to every GTF row",
),
rule_ref(
"missing_transcript_id",
Error,
"GTF",
"A non-gene GTF feature lacks transcript_id",
"Add transcript_id to transcript child rows",
),
rule_ref(
"invalid_coordinate_order",
Error,
"both",
"Feature start is greater than end",
"Swap or correct the feature coordinates",
),
rule_ref(
"non_positive_start",
Error,
"both",
"Feature start is below 1",
"Use 1-based closed coordinates",
),
rule_ref(
"empty_seqid",
Error,
"both",
"Feature seqid is empty",
"Provide chromosome, contig, or scaffold name",
),
rule_ref(
"empty_feature_type",
Error,
"both",
"Feature type is empty",
"Provide a Sequence Ontology style feature type",
),
rule_ref(
"unknown_strand",
Warning,
"both",
"Strand is not one of +, -, ., or ?",
"Normalize strand field",
),
rule_ref(
"score_not_numeric",
Warning,
"both",
"Score is present but not numeric",
"Use a numeric score or '.'",
),
rule_ref(
"reserved_attribute_key",
Warning,
"GFF3",
"Attribute key uses a reserved name unexpectedly",
"Check provider-specific conventions",
),
rule_ref(
"empty_attribute_key",
Error,
"both",
"Attribute key is empty",
"Remove malformed attribute entry",
),
rule_ref(
"empty_required_attribute",
Error,
"both",
"Required attribute has empty value",
"Fill required attribute value",
),
rule_ref(
"duplicate_attribute",
Warning,
"both",
"Same attribute key appears multiple times on one feature",
"Merge values or remove duplicate keys",
),
rule_ref(
"gene_without_transcript",
Warning,
"both",
"Gene has no transcript child",
"Add transcript feature when available",
),
rule_ref(
"transcript_without_exon",
Warning,
"both",
"Transcript has no exon child",
"Add exon intervals",
),
rule_ref(
"cds_without_transcript",
Error,
"both",
"CDS cannot be assigned to a transcript",
"Fix Parent or transcript_id",
),
rule_ref(
"exon_outside_transcript",
Error,
"both",
"Exon lies outside transcript span",
"Correct exon or transcript coordinates",
),
rule_ref(
"cds_outside_exon",
Warning,
"both",
"CDS is not covered by an exon",
"Check coding structure",
),
rule_ref(
"overlapping_exons",
Warning,
"both",
"Transcript exons overlap each other",
"Merge or correct exon intervals",
),
rule_ref(
"unsorted_exons",
Info,
"both",
"Transcript exons are not in genomic order",
"Sort children for deterministic output",
),
rule_ref(
"mixed_seqid_children",
Error,
"both",
"Child feature seqid differs from parent",
"Move child to the correct parent",
),
rule_ref(
"mixed_strand_children",
Warning,
"both",
"Child strand differs from parent",
"Confirm strand conventions",
),
rule_ref(
"unknown_biotype",
Info,
"both",
"Biotype is not in the reference catalog",
"Document project-specific biotype",
),
rule_ref(
"unknown_feature_type",
Info,
"both",
"Feature type is not in the reference catalog",
"Document project-specific feature type",
),
rule_ref(
"missing_name",
Info,
"both",
"Feature lacks display name",
"Add Name or gene_name for user-facing reports",
),
rule_ref(
"large_feature_span",
Info,
"both",
"Feature span is unusually large",
"Check assembly coordinates",
),
rule_ref(
"zero_length_bed_block",
Error,
"both",
"BED block would have zero length",
"Check exon coordinates",
),
rule_ref(
"negative_bed_start",
Error,
"both",
"BED conversion produced negative start",
"Check 1-based start coordinate",
),
rule_ref(
"invalid_target_attribute",
Warning,
"GFF3",
"Target attribute cannot be parsed",
"Use target_id start end strand format",
),
rule_ref(
"invalid_gap_attribute",
Warning,
"GFF3",
"Gap attribute cannot be parsed",
"Use valid GFF3 gap operations",
),
rule_ref(
"invalid_derives_from",
Warning,
"GFF3",
"Derives_from target is missing",
"Add referenced feature or correct value",
),
rule_ref(
"multi_parent_without_split",
Info,
"GFF3",
"Feature has multiple parents",
"Split or document shared feature semantics",
),
rule_ref(
"attribute_needs_escape",
Info,
"GFF3",
"Attribute value contains characters needing escape",
"Use percent encoding in raw GFF3",
),
rule_ref(
"gtf_quote_escape",
Info,
"GTF",
"GTF value contains quotes or backslashes",
"Escape value when writing GTF",
),
rule_ref(
"missing_cds_phase",
Warning,
"both",
"CDS has no phase field",
"Add phase when coding frame is known",
),
rule_ref(
"partial_cds",
Info,
"both",
"CDS appears partial",
"Mark partial status when known",
),
rule_ref(
"missing_protein_id",
Info,
"GTF",
"Coding feature lacks protein_id",
"Add protein_id when available",
),
rule_ref(
"missing_exon_number",
Info,
"GTF",
"Exon lacks exon_number",
"Add exon_number for stable ordering",
),
rule_ref(
"duplicate_exon_number",
Warning,
"GTF",
"Transcript has duplicate exon_number",
"Correct exon numbering",
),
rule_ref(
"inconsistent_gene_name",
Info,
"GTF",
"Rows for a gene use multiple names",
"Normalize gene_name",
),
rule_ref(
"inconsistent_biotype",
Info,
"GTF",
"Rows for a gene use multiple biotypes",
"Normalize gene_biotype",
),
]
}
///|
pub fn find_validation_rule_reference(code : String) -> ValidationRuleReference {
for rule in validation_rule_references() {
if rule.code == code {
return rule
}
}
rule_ref(
code,
Info,
"both",
"Project-specific validation rule",
"Document the rule in project notes",
)
}
///|
pub fn ValidationIssue::rule_reference(
self : ValidationIssue,
) -> ValidationRuleReference {
find_validation_rule_reference(self.code)
}
///|
pub fn validation_rule_references_by_format(
format : String,
) -> Array[ValidationRuleReference] {
let result : Array[ValidationRuleReference] = []
for rule in validation_rule_references() {
if rule.format == format || rule.format == "both" {
result.push(rule)
}
}
result
}
///|
pub fn ValidationRuleReference::to_tsv_row(
self : ValidationRuleReference,
) -> String {
[
self.code,
self.severity.to_string(),
self.format,
self.description,
self.repair_hint,
].join("\t")
}