Changelog
View SourceAll notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
Added -- Cure v0.20.0 catch-up
:bin_segment(M2.1 Core) -- new node type for a single element of a bitstring literal / pattern (<<value::type-size(n)-unit(u)-sign-endian>>). Shape{:bin_segment, meta, [value]}with optional meta keys:type,:signedness,:endianness,:size(AST node),:unit(integer). Added to@core_types, given avalid_node?/3clause, aMetastatic.AST.bin_segment/2builder helper,AST.to_string/1rendering, and handlers in the Cure and ElixirFromMetaadapters.:comment(M2.1 Core) -- new trivia node representing a source comment. Shape{:comment, meta, text}with:comment_kindmeta (:line/:doc/:block). Analyzers and codegens skip comments; formatters and documentation tooling round-trip them. Added to@core_types, given avalid_node?/3clause, theMetastatic.AST.comment/3builder,AST.to_string/1rendering, leaf-safe traversal wiring, and handlers in bothFromMetaadapters (Elixir collapses them tonilbecause its tokenizer strips comments from quoted ASTs).:literalsubtype:bytesdual shape. The validator now accepts either the historicalbinary()payload or a list of:bin_segmentchildren. When the payload is a segment list,AST.traverse/4,AST.prewalker/1,AST.postwalker/1,AST.path/2, andAST.variables/1descend into each segment's value so analyzers see the bound names inside<<x::utf8, rest::binary>>-style patterns.Metastatic.Adapters.Cure.ToMeta-- new abstraction adapter that parses Cure source through the Cure compiler's lexer + parser (when linked in at runtime) and normalises the resulting MetaAST (default:comment_kindmetadata, atom-coerced:bin_segmentspecifiers, recursive:paramnormalisation). Exposesfrom_source/2,from_ast/1, andnormalize/1.Metastatic.Adapters.Cure.abstract/3-- routes through the newToMeta.from_source/2, threads thepreserve_comments:option, and returns aDocumentwithmetadata: %{language: :cure}so the result round-trips cleanly throughAdapter.round_trip/2.METAST_SPEC.md-- adds dedicated:bin_segmentand:commentsubsections under M2.1 Core, documents the dual:bytespayload, and updates the Node Type Reference table.
Added -- previously unreleased
- MetaAST nodes backported from Cure v0.18.0 -- v0.19.0:
:pin(M2.2 Extended) -- pattern-position pin operator^x. Shape{:pin, meta, [inner]}. Promoted from a dead placeholder entry in the Elixir adapter to a first-class node type recognised byMetastatic.AST.conforms?/1.:assert_type(M2.2 Extended) -- compile-time type assertionassert_type expr : T. Shape{:assert_type, meta, [expr, type_ast]}. Reified by the Cure adapter; dropped toexprby the Elixir adapter (Elixir has no surface syntax for it).container_type: :proof-- new value of the:containermetadata key emitted by Cure forproof Name.Pathcontainers. Structurally identical to:modulebut semantically a proposition-level namespace.
- MetaAST nodes backported from earlier Cure releases:
:record_update(M2.2s Structural, Cure v0.15.0) -- functional record updateName{base | field: val, ...}. Shape{:record_update, [name: "Name", ...], [base | field_pairs]}.container_type: :fsm(Cure v0.7.0) -- finite state machine containerfsm Name with Payload. Carries optional FSM metadata (:payload,:terminal_states,:invariants,:verify,:timer,:on_transition,:on_enter,:on_exit,:on_failure,:on_timer); transitions are:function_callnodes with:from,:event,:to, and:event_kindmetadata.
Metastatic.Adapters.Cure.FromMetanow reifies:pin,:assert_type,:record_update, andcontainer_type: :proof/:fsminstead of falling back toinspect/1. The newemit_fsm/3helper renders the container header (fsm Name [with Payload]), the transition body, the optional@timer <ms>annotation, and anyon_transition/on_enter/on_exit/on_failure/on_timercallback blocks.- Macro-like AST traversal and manipulation API -- mirrors Elixir's
Macromodule for MetaAST:prewalk/2,postwalk/2-- transform-only tree walks (no accumulator)prewalker/1,postwalker/1-- lazy enumerable traversals (Stream-based)path/2-- find the path from a matching node up to the rootunpipe/1-- flatten nested:pipechains into a list of{node, position}tuplespipe_into/3-- inject an expression into a:function_callargument list at a given positiondecompose_call/1-- extract{name, args}from:function_callnodes (returns:errorotherwise)to_string/1-- human-readable pseudo-code representation of MetaAST for debuggingliteral?/1-- recursively check whether a subtree is composed entirely of literal valuesoperator?/1-- predicate for:binary_opand:unary_opnodesvalidate/1-- structural validation returning:okor{:error, {:invalid_node, node}}unique_var/1-- generate unique variable nodes with monotonic counter
- All new functions available on both
Metastatic.AST(canonical) andMetastatic(convenience delegates) - Full
@doc,@spec, and doctests for every new function - 1992 tests passing (336 doctests + 1656 tests), zero regressions
Documentation
- Added "AST Traversal & Manipulation" section to README.md explaining why traversal matters and showing walking, lazy enumeration, path-finding, pipe utilities, predicates, and inspection
- Added "AST Traversal & Manipulation" section to GETTING_STARTED.md with comprehensive examples for every new function and a quick-reference list
[0.15.1] - 2026-04-12
Major adapter overhaul: all five language adapters now emit proper M2 types instead of falling back
to :language_specific, alongside new M2 node types, Erlang adapter expansion, and comprehensive
documentation with mermaid diagrams. 1919 tests passing (263 doctests + 1656 tests), zero regressions.
Added
- New M2 node types:
:throw(M2.1 Core) -- raise/throw across languages:yield(M2.2 Extended) -- generators (yield/yield_from):decorator(M2.2s Structural) -- decorators/annotations
:bitwiseoperator category forband,bor,bxor,bsl,bsr,<<,>>- Expanded
container_type::interface,:trait,:protocol,:enum,:struct - New literal subtypes:
:char,:bytes - New loop types:
:do_while,:infinite - Expanded
import_type::from,:module,:export - Builder helpers:
throw_node/3,yield_node/3,decorator/3 - Erlang adapter:
-module(Name)->:container; function defs ->:function_defwith params;funexpressions ->:lambda;fun Name/Arity->:lambdawithcapture_form;try/catch/after->:exception_handling;#{...}->:mapwith:pairchildren;-export([...])->:importwith export type;receiveremains:language_specific - Python
withstatement ->:blockwith[original_form: :with]and inline_match bindings - Mermaid diagrams throughout:
GETTING_STARTED.md,RESEARCH.md,METAST_SPEC.md,SUPPLEMENTAL_MODULES.md, module docstrings (ast.ex,adapter.ex,validator.ex), and mix task docs
Changed
- Ruby adapter:
dstr->:string_interpolation;irange/erange->:rangewith[inclusive: true/false];break/next->:early_returnwith[kind: :break/:continue];regexp->:literalwith[subtype: :regex, flags: [...]];<</>>->category: :bitwise; round-trip (from_meta) support added for all new types - Python adapter: All comprehensions (
ListComp/DictComp/SetComp/GeneratorExp) ->:comprehensionwith proper:generator/:filterchildren;match(3.10+) ->:pattern_matchwith:match_armchildren;AugAssign->:augmented_assignment;NamedExpr(walrus:=) ->:inline_match;Raise->:throw;Yield/YieldFrom->:yield;AsyncFunctionDef->:function_defwith[async: true]; decorated functions/classes -> proper M2 nodes with[decorators: [...]] - Haskell adapter: modules ->
:containerwithcontainer_type: :module; function bindings ->:function_def; type signatures ->:type_annotationwith[annotation_type: :spec]; list comprehensions ->:comprehensionwith[comp_type: :list];class_decl->:containerwithcontainer_type: :interface - Erlang adapter: bitwise ops ->
category: :bitwise; char literals ->subtype: :char - 1919 tests passing (263 doctests + 1656 tests), zero regressions
[0.12.1] - 2026-03-24
Added
- Comprehensive Ruby/Rails Support - Major expansion of the Ruby adapter:
- Safe navigation operator (
&.) viacsendAST type: maps tofunction_call/attribute_accesswithnull_safe: true - Conditional assignment operators:
||=(or_asgn) and&&=(and_asgn) map toaugmented_assignment - All Ruby parameter types:
optarg,kwarg,kwoptarg,restarg,kwrestarg,blockarg,forward_arg - Variable binding forms for
ivasgn,cvasgn,gvasgn(1-child targets in||=/&&=) - Multi-statement
kwbeginblocks (explicitbegin...end) - FromMeta round-trip:
csendreconstruction,or_asgn/and_asgnreconstruction, all parameter types - Fixed fragile
collection_opfrom_meta lambda extraction - Parser now emits
end_lineandend_columnin location info - 3 Rails fixture files for testing (model, concern, service)
- 41 new tests including integration tests against 53-file Rails app (51/53 transform successfully)
- Test suite: 255 doctests + 1646 tests, 0 failures
- Safe navigation operator (
[0.12.0] - 2026-03-19
Added
- OpKind Semantic Metadata System - Semantic operation kind metadata for accurate code analysis:
- New
Metastatic.Semantic.OpKindmodule providing semantic meaning for function calls and operations - Supports 7 domains:
:db,:http,:auth,:cache,:queue,:file,:external_api - Rich operation types for each domain (e.g., DB: retrieve, retrieve_all, query, create, update, delete, transaction, preload, aggregate)
- Framework-aware detection (Ecto, Django, Sequelize, ActiveRecord, etc.)
- OpKind stored in
:op_kindmetadata field of:function_callnodes - 5 business logic analyzers updated to use OpKind with semantic-first, heuristic-fallback pattern:
- BlockingInPlug: Checks OpKind domain for blocking operations
- MissingTelemetryForExternalHttp: Uses OpKind.http?() for HTTP detection
- SyncOverAsync: Identifies blocking operations via OpKind domain
- InefficientFilter: Detects fetch-all operations via OpKind (domain: :db, operation: :retrieve_all/:query)
- TOCTOU: Identifies file check/use operations via OpKind
- Significantly improves analyzer accuracy while maintaining backward compatibility
- Example:
{:function_call, [name: "Repo.get", op_kind: [domain: :db, operation: :retrieve, target: "User"]], [args...]}
- New
Changed
- Uniform 3-Tuple MetaAST Format - Complete migration to
{type_atom, keyword_meta, children_or_value}structure:- All MetaAST nodes now use a uniform 3-tuple format for consistency and easier pattern matching
- Metadata moved to keyword lists in the second element (e.g.,
[subtype: :integer],[operator: :+]) - Children/value in the third element (list for composites, value for leaves)
- Updated all 5 language adapters (Python, Elixir, Ruby, Erlang, Haskell) to produce 3-tuple output
- Updated all 9 analysis tools (complexity, duplication, metrics, etc.) for new format
- Updated all 20 business logic analyzers for new format:
- SwallowingException: Updated
exception_handlingpattern matching - NPlusOneQuery: Fixed lambda detection with
Keyword.keyword?check - InefficientFilter: Added handler for
function_defbodies - TelemetryInRecursiveFunction: Fixed body traversal through all children
- MissingPreload: Updated
collection_opformat handling
- SwallowingException: Updated
- Fixed Elixir adapter try/rescue transformation with pre_transform marker
- Fixed
extract_module_name/1to handle{:literal, _, atom}format - Test suite: 1,422 tests passing (235 doctests + 1,187 tests, 100% coverage)
Added
- M1 Metadata Preservation - Full context threading for Ragex integration:
- Expanded location type with optional M1 context fields:
:language,:module,:function,:arity,:container,:visibility,:file,:m1_meta - Added AST helper functions:
with_context/2,extract_metadata/2,node_module/1,node_function/1,node_arity/1,node_file/1,node_container/1,node_visibility/1 - Elixir adapter now attaches module and function context to structural nodes (container, function_def)
- Runner properly handles location-aware nodes (both with and without metadata) in
update_contexts/2andextract_children/2 - Analyzer.issue/1 helper automatically extracts location metadata from nodes
- Updated TelemetryInRecursiveFunction analyzer to handle both 6-tuple and 7-tuple function_def patterns
- All 1,431 tests passing (202 doctests + 1,229 tests including 14 new metadata tests)
- Enables Ragex to access function names, arities, modules, and locations from business logic analyzers
- Expanded location type with optional M1 context fields:
- Business Logic Analyzers - 20 language-agnostic analyzers ported from oeditus_credo:
- Tier 1 (Pure MetaAST, 9 analyzers): CallbackHell, MissingErrorHandling, SilentErrorCase, SwallowingException, HardcodedValue, NPlusOneQuery, InefficientFilter, UnmanagedTask, TelemetryInRecursiveFunction
- Tier 2 (Function Name Heuristics, 4 analyzers): MissingTelemetryForExternalHttp, SyncOverAsync, DirectStructUpdate, MissingHandleAsync
- Tier 3 (Naming Conventions, 4 analyzers): BlockingInPlug, MissingTelemetryInAuthPlug, MissingTelemetryInLiveviewMount, MissingTelemetryInObanWorker
- Tier 4 (Content Analysis, 3 analyzers): MissingPreload, InlineJavascript, MissingThrottle
- Each analyzer includes comprehensive cross-language examples (Python, JavaScript, Elixir, C#, Go, Java, Ruby, Rust)
- Total: ~4,800 lines across 20 analyzer modules
- All 1,282 tests passing (142 doctests + 1,140 tests)
- Demonstrates that business logic analysis is fundamentally language-agnostic
- M2.1 Core Layer enhancements:
listtype for list/array literals (moved from literal collection to first-class core type)maptype for map/dictionary/object literals (moved from literal collection to first-class core type)- Updated all language adapters (Python, Elixir) to use new list/map types
- Updated all analysis modules to traverse list elements and map key-value pairs
- Updated validator to classify list/map as core layer
- Updated CLI tools (inspector, formatter) to handle list/map display
- Added 12 new tests for list/map functionality (1,356 total tests passing: 131 doctests + 1,225 tests)
- M2.2s Structural/Organizational Layer - New meta-model layer for cross-language structural constructs
containertype for modules/classes/namespaces with visibility-aware member trackingfunction_deftype for function/method definitions with guards, visibility, and pattern parametersattribute_accesstype for field/property access on objectsaugmented_assignmenttype for compound assignment operators (+=, -=, etc.)propertytype for property declarations with getters/setters
- Full support for M2.2s types across all analysis modules:
- Duplication fingerprinting (Type I/II clone detection)
- Cyclomatic complexity analysis
- Cognitive complexity analysis
- Nesting depth tracking
- Halstead metrics (operators/operands)
- Function metrics (statements, returns)
- Lines of code (LoC) counting
- Comprehensive test coverage: 143 new tests for structural types (1,149 total tests passing)
- Helper functions:
container_name/1,function_name/1,function_visibility/1,has_state?/1
Documentation
- Added
STRUCTURAL_LAYER_RESEARCH.md- Theory and cross-language analysis of structural constructs - Added
STRUCTURAL_LAYER_DESIGN.md- Implementation design decisions and rationale - Updated
README.mdwith M2.2s layer description - Enhanced
@typedocfor all structural types with M1 instances and examples
Mix Tasks
- All 15 mix tasks now have comprehensive
@moduledocdocumentation and@impl Mix.Task - Added ruby and haskell language support to
analyze,complexity,purity_check,translate,validate_equivalence detect_duplicatesnow fully implemented - parses real source files via language adapters
[0.1.0] - 2026-01-21
MVP
Notes
This project follows a rigorous theoretical foundation based on:
- OMG Meta Object Facility (MOF) Specification
- Eclipse Modeling Framework (EMF)
- Formal meta-modeling theory
See THEORETICAL_FOUNDATIONS.md for the complete formal treatment with proofs.