Search documentation of Metastatic

# Metastatic.Semantic.Enricher (Metastatic v0.13.2)

View Source

AST enricher for semantic metadata injection.

This module provides functions to enrich MetaAST nodes with semantic operation metadata (`op_kind`). It is designed to be called during adapter transformations (in `to_meta`) to eagerly annotate function calls with their semantic meaning.

## Usage

### Single Node Enrichment

    alias Metastatic.Semantic.Enricher

    # Enrich a single function_call node
    enriched = Enricher.enrich(node, :elixir)

### Full Tree Enrichment

    # Enrich all nodes in an AST tree
    enriched_ast = Enricher.enrich_tree(ast, :python)

## Integration with Adapters

The enricher should be called at the end of the `to_meta` transformation:

    def transform(native_ast) do
      with {:ok, meta_ast, metadata} <- do_transform(native_ast) do
        enriched = Enricher.enrich_tree(meta_ast, :python)
        {:ok, enriched, metadata}
      end
    end

## Enrichment Strategy

Enrichment is eager - all applicable nodes are enriched in a single pass. This ensures semantic information is available immediately for analyzers.

Only `:function_call` nodes are currently enriched. The enricher:

1. Extracts the function name from metadata
2. Matches against registered patterns for the source language
3. If matched, adds `op_kind` to the node's metadata
4. Extracts target entity from arguments when possible

## Summary

### Types

language()

Language identifier for pattern matching

### Functions

enrich(node, language)

Enriches a single MetaAST node with semantic metadata.

enrich_tree(ast, language)

Enriches an entire AST tree with semantic metadata.

enriched?(arg1)

Checks if a node has been enriched with semantic metadata.

get_op_kind(arg1)

Gets the op_kind from a node, if present.

## Types

# language()

    @type language() :: Metastatic.Semantic.Patterns.language()

Language identifier for pattern matching

## Functions

# enrich(node, language)

    @spec enrich(Metastatic.AST.meta_ast(), language()) :: Metastatic.AST.meta_ast()

Enriches a single MetaAST node with semantic metadata.

If the node is a `:function_call` and matches a known pattern for the given language, adds `op_kind` metadata. Otherwise returns the node unchanged.

## Parameters

- `node` - The MetaAST node to enrich
- `language` - The source language for pattern matching

## Examples

    iex> node = {:function_call, [name: "Repo.get"], [{:variable, [], "User"}, {:literal, [subtype: :integer], 1}]}
    iex> enriched = Enricher.enrich(node, :elixir)
    iex> Keyword.get(elem(enriched, 1), :op_kind)
    [domain: :db, operation: :retrieve, target: "User", async: false, framework: :ecto]

# enrich_tree(ast, language)

    @spec enrich_tree(Metastatic.AST.meta_ast(), language()) :: Metastatic.AST.meta_ast()

Enriches an entire AST tree with semantic metadata.

Traverses the AST and enriches all applicable nodes. This is the recommended way to enrich AST during adapter transformations.

## Parameters

- `ast` - The root MetaAST node
- `language` - The source language for pattern matching

## Examples

    iex> ast = {:block, [], [
    ...>   {:function_call, [name: "Repo.get"], [{:variable, [], "User"}, {:literal, [subtype: :integer], 1}]},
    ...>   {:function_call, [name: "Repo.all"], [{:variable, [], "Post"}]}
    ...> ]}
    iex> enriched = Enricher.enrich_tree(ast, :elixir)
    iex> {:block, [], [call1, call2]} = enriched
    iex> Keyword.get(elem(call1, 1), :op_kind) |> Keyword.get(:operation)
    :retrieve
    iex> Keyword.get(elem(call2, 1), :op_kind) |> Keyword.get(:operation)
    :retrieve_all

# enriched?(arg1)

    @spec enriched?(Metastatic.AST.meta_ast()) :: boolean()

Checks if a node has been enriched with semantic metadata.

## Examples

    iex> node = {:function_call, [name: "Repo.get", op_kind: [domain: :db, operation: :retrieve]], []}
    iex> Enricher.enriched?(node)
    true

    iex> node = {:function_call, [name: "unknown"], []}
    iex> Enricher.enriched?(node)
    false

# get_op_kind(arg1)

    @spec get_op_kind(Metastatic.AST.meta_ast()) :: Metastatic.Semantic.OpKind.t() | nil

Gets the op_kind from a node, if present.

## Examples

    iex> node = {:function_call, [name: "Repo.get", op_kind: [domain: :db, operation: :retrieve]], []}
    iex> Enricher.get_op_kind(node)
    [domain: :db, operation: :retrieve]

    iex> node = {:function_call, [name: "unknown"], []}
    iex> Enricher.get_op_kind(node)
    nil