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}