// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2026 clbbbb
///|
pub fn simplify_text(text : String) -> String {
match parse(text).expr {
Some(expr) => format(simplify_expr(expr))
None => ""
}
}
///|
pub fn simplify_expr(expr : Expr) -> Expr {
match expr {
License(id) => License(canonical_license(id))
LicenseWithException(id, ex) =>
LicenseWithException(canonical_license(id), canonical_exception(ex))
And(left, right) => simplify_and(simplify_expr(left), simplify_expr(right))
Or(left, right) => simplify_or(simplify_expr(left), simplify_expr(right))
}
}
///|
pub fn simplify_and(left : Expr, right : Expr) -> Expr {
if format(left) == format(right) {
left
} else {
And(left, right)
}
}
///|
pub fn simplify_or(left : Expr, right : Expr) -> Expr {
if format(left) == format(right) {
left
} else {
Or(left, right)
}
}
///|
pub fn alternatives(expr : Expr) -> Array[Expr] {
match expr {
Or(left, right) => alternatives(left) + alternatives(right)
_ => [expr]
}
}
///|
pub fn requirements(expr : Expr) -> Array[Expr] {
match expr {
And(left, right) => requirements(left) + requirements(right)
_ => [expr]
}
}
///|
pub fn alternative_texts(text : String) -> Array[String] {
match parse(text).expr {
Some(expr) => {
let rows : Array[String] = []
for item in alternatives(expr) {
rows.push(format(simplify_expr(item)))
}
unique_strings(rows)
}
None => []
}
}
///|
pub fn requirement_texts(text : String) -> Array[String] {
match parse(text).expr {
Some(expr) => {
let rows : Array[String] = []
for item in requirements(expr) {
rows.push(format(simplify_expr(item)))
}
unique_strings(rows)
}
None => []
}
}
///|
pub fn expression_shape(text : String) -> String {
match parse(text).expr {
Some(expr) => expression_shape_expr(expr)
None => "invalid"
}
}
///|
pub fn expression_shape_expr(expr : Expr) -> String {
match expr {
License(_) => "single"
LicenseWithException(_, _) => "single-with-exception"
And(_, _) if contains_string(operators(expr), "OR") => "mixed"
And(_, _) => "all-of"
Or(_, _) if contains_string(operators(expr), "AND") => "mixed"
Or(_, _) => "any-of"
}
}
///|
pub fn choice_count(text : String) -> Int {
match parse(text).expr {
Some(expr) => alternatives(expr).length()
None => 0
}
}
///|
pub fn requirement_count(text : String) -> Int {
match parse(text).expr {
Some(expr) => requirements(expr).length()
None => 0
}
}
///|
pub fn explain_expression(text : String) -> String {
match parse(text).expr {
Some(expr) => {
let rows : Array[String] = [
"normalized: " + format(expr),
"simplified: " + format(simplify_expr(expr)),
"shape: " + expression_shape_expr(expr),
"alternatives: " + join_with(alternative_texts(text), " | "),
"requirements: " + join_with(requirement_texts(text), " + "),
]
join_lines(rows)
}
None => "parse error: " + parse(text).error
}
}