relay-knowledge 1.1.6

Graph-database-based knowledge graph project.
Documentation
const CONFIG_EXTENSIONS: &[&str] = &[
    ".toml",
    ".yaml",
    ".yml",
    ".json",
    ".env",
    ".ini",
    ".properties",
];

pub(super) fn boolean_config_keys(line: &str) -> Vec<String> {
    let trimmed = line.trim();
    let mut keys = Vec::new();
    if let Some(key) = direct_boolean_config_key(trimmed) {
        push_unique(&mut keys, key);
    }
    for key in inline_boolean_config_keys(trimmed) {
        push_unique(&mut keys, key);
    }

    keys
}

fn direct_boolean_config_key(trimmed: &str) -> Option<String> {
    let separator = trimmed
        .find('=')
        .or_else(|| trimmed.find(':'))
        .filter(|index| *index > 0)?;
    let (key, value) = trimmed.split_at(separator);
    let key = key.trim().trim_matches('"').trim_matches('\'');
    let value = value[1..]
        .trim()
        .trim_end_matches(',')
        .trim_matches('"')
        .trim_matches('\'');
    if !matches!(value, "true" | "false" | "enabled" | "disabled") || key.is_empty() {
        return None;
    }
    if key
        .chars()
        .all(|character| character.is_ascii_alphanumeric() || matches!(character, '_' | '-' | '.'))
    {
        Some(key.to_owned())
    } else {
        None
    }
}

fn inline_boolean_config_keys(line: &str) -> Vec<String> {
    let mut keys = Vec::new();
    for value_start in boolean_value_starts(line) {
        let prefix = line[..value_start].trim_end();
        let Some(separator) = prefix.rfind(['=', ':']) else {
            continue;
        };
        if !prefix[separator.saturating_add(1)..].trim().is_empty() {
            continue;
        }
        let Some(key) = prefix[..separator]
            .trim_end()
            .rsplit(|character: char| {
                character.is_whitespace() || matches!(character, '{' | '[' | ',')
            })
            .next()
        else {
            continue;
        };
        let key = key.trim().trim_matches('"').trim_matches('\'');
        if valid_config_key(key) {
            push_unique(&mut keys, key.to_owned());
        }
    }

    keys
}

fn boolean_value_starts(line: &str) -> Vec<usize> {
    let mut starts = Vec::new();
    let mut quote = None;
    let mut escaped = false;
    let mut index = 0usize;
    while index < line.len() {
        let rest = &line[index..];
        let Some(character) = rest.chars().next() else {
            break;
        };
        if let Some(quote_character) = quote {
            if escaped {
                escaped = false;
            } else if character == '\\' {
                escaped = true;
            } else if character == quote_character {
                quote = None;
            }
            index = index.saturating_add(character.len_utf8());
            continue;
        }
        if character == '"' || character == '\'' {
            quote = Some(character);
            index = index.saturating_add(character.len_utf8());
            continue;
        }
        for marker in ["true", "false", "enabled", "disabled"] {
            if rest.starts_with(marker)
                && token_boundary_before(line, index)
                && token_boundary_after(line, index + marker.len())
            {
                starts.push(index);
            }
        }
        index = index.saturating_add(character.len_utf8());
    }
    starts.sort_unstable();
    starts
}

fn token_boundary_before(line: &str, start: usize) -> bool {
    line[..start]
        .chars()
        .next_back()
        .is_none_or(|character| !is_config_token_character(character))
}

fn token_boundary_after(line: &str, end: usize) -> bool {
    line[end..]
        .chars()
        .next()
        .is_none_or(|character| !is_config_token_character(character))
}

fn is_config_token_character(character: char) -> bool {
    character.is_ascii_alphanumeric() || matches!(character, '_' | '-' | '.')
}

fn valid_config_key(key: &str) -> bool {
    !key.is_empty()
        && key.chars().all(|character| {
            character.is_ascii_alphanumeric() || matches!(character, '_' | '-' | '.')
        })
}

fn push_unique(values: &mut Vec<String>, value: String) {
    if !values.iter().any(|existing| existing == &value) {
        values.push(value);
    }
}

pub(super) fn looks_like_config_file(path: &str) -> bool {
    CONFIG_EXTENSIONS
        .iter()
        .any(|extension| path.ends_with(extension))
}