fn lift_enum_descriptions()

in compiler-rs/clients_schema_to_openapi/src/schemas.rs [547:635]


fn lift_enum_descriptions(prop: &Property, model: &clients_schema::IndexedModel) -> anyhow::Result<Option<String>> {

    // FIXME: could be memoized on `prop.typ` as we'll redo this work every time we encounter the same value definition
    let value = &prop.typ;

    // Maybe an alias pointing to an array or lenient array
    let value = unwrap_alias(value, model)?.unwrap_or(value);

    // Unwrap lenient array
    let (lenient_array, value) = match unwrap_lenient_array(value) {
        Some(lenient_array) => (true, lenient_array),
        None => (false, value),
    };

    // Unwrap array to get to the enum type
    let value = unwrap_array(value).unwrap_or(value);

    // Unwrap aliases again, in case the array value was itself an alias
    let value = unwrap_alias(value, model)?.unwrap_or(value);

    // Is this an enum?
    let ValueOf::InstanceOf(inst) = value else {
        return Ok(None);
    };

    if inst.typ.is_builtin() {
        return Ok(None);
    }

    let TypeDefinition::Enum(enum_def) = model.get_type(&inst.typ)? else {
        return Ok(None);
    };

    let mut result: String = match &prop.description {
        Some(desc) => desc.clone(),
        None => String::new(),
    };

    // Do we have at least one enum member description?
    if enum_def.members.iter().any(|m| m.description.is_some()) {
        // Some descriptions: output a list with descriptions

        // Close description paragraph and add an empty line to start a new paragraph
        writeln!(result)?;
        writeln!(result)?;

        writeln!(result, "Supported values include:")?;
        for member in &enum_def.members {
            write!(result, "  - ")?;
            value_and_aliases(&mut result, member)?;
            if let Some(desc) = &member.description {
                write!(result, ": {}", desc)?;
            }
            writeln!(result)?;
        }
        writeln!(result)?;

    } else {
        // No description: inline list of values, only if this wasn't a lenient array.
        // Otherwise (enum or enum array), bump.sh will correctly output a list of possible values.
        if !lenient_array {
            return Ok(None);
        }

        // Close description paragraph and add an empty line to start a new paragraph
        writeln!(result)?;
        writeln!(result)?;

        write!(result, "Supported values include: ")?;
        for (idx, member) in enum_def.members.iter().enumerate() {
            if idx > 0 {
                write!(result, ", ")?;
            }
            value_and_aliases(&mut result, member)?;
        }
        write!(result, "\n\n")?;
    }

    fn value_and_aliases(out: &mut String, member: &EnumMember) -> anyhow::Result<()> {
        write!(out, "`{}`", member.name)?;
        if !member.aliases.is_empty() {
            write!(out, " (or `{}`)", member.aliases.join("`, `"))?;
        }

        Ok(())
    }

    Ok(Some(result))
}