Skip to main content

backhopper_core/
extract.rs

1// Copyright (C) 2026 Michael S. Klishin and Contributors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// See LICENSE-APACHE and LICENSE-MIT for details.
4
5//! Shared surface for the per-language source extractors.
6//!
7//! The token-driven Erlang scanner (`backhopper-erlang`) and the
8//! regex-driven Elixir scanner (`backhopper-elixir`) keep their own bodies,
9//! but speak this common vocabulary: the decode error, the extracted-source
10//! bag, and the visibility classifier.
11
12use thiserror::Error;
13
14use crate::model::names::{ApplicationName, ModuleName, RelativePath};
15use crate::model::snapshot::{HrlFile, Module, Visibility};
16
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct ScannedFile {
19    pub path: RelativePath,
20    pub app: ApplicationName,
21    pub bytes: Vec<u8>,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct ExtractedSource {
26    pub modules: Vec<Module>,
27    pub headers: Vec<HrlFile>,
28}
29
30#[derive(Debug, Error)]
31pub enum ExtractError {
32    #[error("invalid utf-8 in {path} at byte offset {offset}")]
33    InvalidUtf8 { path: RelativePath, offset: usize },
34}
35
36/// Resolves a module's [`Visibility`] from its name, the config's public and
37/// internal module lists, an out-of-band `hidden` hint (Erlang `%% @hidden`
38/// or `-doc(hidden)`, Elixir `@moduledoc false`), and whether its only
39/// exports are `-ifdef(TEST)`-guarded. An explicit internal listing wins; a
40/// public listing overrides the `hidden` hint.
41pub fn classify_visibility(
42    module: &ModuleName,
43    hidden: bool,
44    test_only: bool,
45    public_modules: &[ModuleName],
46    internal_modules: &[ModuleName],
47) -> Visibility {
48    if internal_modules.contains(module) {
49        return Visibility::Hidden;
50    }
51    if hidden && !public_modules.contains(module) {
52        return Visibility::Hidden;
53    }
54    if test_only {
55        return Visibility::TestOnly;
56    }
57    Visibility::Public
58}