Skip to main content

tfparser_core/loader/
raw.rs

1//! Loader output: a [`RawComponent`] containing every block lowered to our
2//! own IR.
3//!
4//! Per [12-hcl-loader.md § 2], the loader's contract is "no `hcl_edit` types
5//! escape this struct" (invariant I-LOAD-2). Downstream phases consume only
6//! [`RawBlock`] / [`crate::ir::Expression`] / [`crate::ir::Value`].
7//!
8//! [12-hcl-loader.md § 2]: ../../../specs/12-hcl-loader.md
9
10use std::{path::Path, sync::Arc};
11
12use crate::{
13    Diagnostic,
14    ir::{AttributeMap, BlockKind, ComponentKind, Span},
15};
16
17/// A lowered HCL block.
18#[derive(Clone, Debug, PartialEq)]
19#[non_exhaustive]
20pub struct RawBlock {
21    /// What kind of block (resource, data, variable, …). [`BlockKind::Unknown`]
22    /// for anything we did not recognise (e.g. user-defined `dynamic`
23    /// blocks).
24    pub kind: BlockKind,
25
26    /// Block labels, in source order (`["aws_db_instance", "this"]` for a
27    /// resource, `["root"]` for a Terragrunt `include "root"`, etc.).
28    pub labels: Vec<Arc<str>>,
29
30    /// Top-level attributes of the block body. Nested blocks land as
31    /// [`crate::ir::Value::Map`] entries inside an
32    /// [`crate::ir::Expression::Literal`] under a synthetic key (block
33    /// identifier).
34    pub body: AttributeMap,
35
36    /// Span of the block keyword.
37    pub span: Span,
38
39    /// Source file that contained the block. Held as `Arc<Path>` so the
40    /// downstream IR does not double-allocate.
41    pub source: Arc<Path>,
42}
43
44/// One discovered + parsed component, post-loader.
45///
46/// Carries the **flat** list of every block in every file (preserving file
47/// order and within-file order), plus any non-fatal diagnostics surfaced
48/// during parse / lowering.
49///
50/// The downstream phases derive `Component`, `Resource[]`, `ProviderBlock[]`,
51/// etc. by walking `raw_blocks` — that projection is Phase 3 work.
52#[derive(Clone, Debug, PartialEq)]
53#[non_exhaustive]
54pub struct RawComponent {
55    /// Path of the component dir, relative to the workspace root.
56    pub path: Arc<Path>,
57
58    /// Whether the discoverer classified this as a component or a module.
59    pub kind: ComponentKind,
60
61    /// All lowered blocks, file-order then within-file-order.
62    pub raw_blocks: Vec<RawBlock>,
63
64    /// Per-file parse / limit diagnostics. Surfaced upward into
65    /// `Workspace.diagnostics` by the orchestrator.
66    pub diagnostics: Vec<Diagnostic>,
67}
68
69impl RawComponent {
70    /// Construct an empty [`RawComponent`] for `path`. The loader uses this
71    /// as a starting point and pushes blocks / diagnostics during the walk.
72    #[must_use]
73    pub fn new(path: Arc<Path>, kind: ComponentKind) -> Self {
74        Self {
75            path,
76            kind,
77            raw_blocks: Vec::new(),
78            diagnostics: Vec::new(),
79        }
80    }
81}