Skip to content

Terraform Parser

jnkn.parsing.terraform.parser

Terraform Language Parser.

Handles parsing of Terraform configuration files (.tf) and JSON plans. Uses specialized extractors for resources, variables, outputs, and modules.

Classes

TerraformParser

Bases: LanguageParser

Static analysis parser for Terraform HCL files.

Source code in src/jnkn/parsing/terraform/parser.py
class TerraformParser(LanguageParser):
    """
    Static analysis parser for Terraform HCL files.
    """

    def __init__(self, context: ParserContext | None = None):
        super().__init__(context)
        self._extractors = ExtractorRegistry()
        self._register_extractors()

    def _register_extractors(self) -> None:
        """Register the standard suite of Terraform extractors."""
        self._extractors.register(ResourceExtractor())
        self._extractors.register(OutputExtractor())
        self._extractors.register(VariableExtractor())
        self._extractors.register(ModuleExtractor())
        self._extractors.register(DataSourceExtractor())
        self._extractors.register(LocalsExtractor())
        self._extractors.register(ReferenceExtractor())

    @property
    def name(self) -> str:
        return "terraform"

    @property
    def extensions(self) -> List[str]:
        return [".tf"]

    def can_parse(self, file_path: Path, content: bytes | None = None) -> bool:
        return file_path.suffix == ".tf"

    def parse(self, file_path: Path, content: bytes) -> Generator[Union[Node, Edge], None, None]:
        try:
            text = content.decode(self.context.encoding)
        except UnicodeDecodeError:
            return

        file_id = f"file://{file_path}"

        # Create the file node
        yield Node(
            id=file_id,
            name=file_path.name,
            type=NodeType.CODE_FILE,
            path=str(file_path),
            metadata={"language": "hcl"},
        )

        # Execute extractors
        ctx = ExtractionContext(file_path=file_path, file_id=file_id, text=text, seen_ids=set())

        yield from self._extractors.extract_all(ctx)

TerraformPlanParser

Bases: LanguageParser

Parser for Terraform JSON plan output (tfplan.json).

Source code in src/jnkn/parsing/terraform/parser.py
class TerraformPlanParser(LanguageParser):
    """
    Parser for Terraform JSON plan output (tfplan.json).
    """

    @property
    def name(self) -> str:
        return "terraform_plan"

    @property
    def extensions(self) -> List[str]:
        return [".json"]

    def can_parse(self, file_path: Path, content: bytes | None = None) -> bool:
        """
        Check if file is a Terraform plan JSON.
        Uses heuristics on filename and content structure.
        """
        if file_path.suffix == ".json" and "plan" in file_path.name.lower():
            return True

        if content:
            try:
                start = content[:200].decode("utf-8", errors="ignore")
                return "resource_changes" in start or "terraform_version" in start
            except Exception:
                pass
        return False

    def parse(self, file_path: Path, content: bytes) -> List[Union[Node, Edge]]:
        results = []
        try:
            plan = json.loads(content)
        except json.JSONDecodeError:
            return []

        if "resource_changes" not in plan:
            return []

        for change in plan["resource_changes"]:
            res_type = change.get("type")
            res_name = change.get("name")
            address = change.get("address")

            if not res_type or not res_name:
                continue

            node_id = f"infra:{res_type}.{res_name}"

            node = Node(
                id=node_id,
                name=res_name,
                type=NodeType.INFRA_RESOURCE,
                metadata={
                    "terraform_address": address,
                    "change_actions": change.get("change", {}).get("actions", []),
                },
            )
            results.append(node)

        return results
Functions
can_parse(file_path, content=None)

Check if file is a Terraform plan JSON. Uses heuristics on filename and content structure.

Source code in src/jnkn/parsing/terraform/parser.py
def can_parse(self, file_path: Path, content: bytes | None = None) -> bool:
    """
    Check if file is a Terraform plan JSON.
    Uses heuristics on filename and content structure.
    """
    if file_path.suffix == ".json" and "plan" in file_path.name.lower():
        return True

    if content:
        try:
            start = content[:200].decode("utf-8", errors="ignore")
            return "resource_changes" in start or "terraform_version" in start
        except Exception:
            pass
    return False