Repository navigation
feat: add Rust, Solidity, and Dart scanner adapters - #44
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 11b8fac670
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| first = parts[0] | ||
| return "lib/shared" if first == "shared" else first |
There was a problem hiding this comment.
Derive layers relative to each source root
When a conventional manifest uses sourceRoots: ["lib"], scan_repo passes repository-relative paths such as lib/core/api.dart, so this selects lib rather than the intended core layer described above. The identical helpers in the new Rust and Solidity adapters flatten typical src/decision/... and src/core/... trees to src as well, making the generated architecture maps lose their layer distinctions; strip the active source-root prefix before inferring the layer.
Useful? React with 👍 / 👎.
| EXPORT_STRUCT_RE = re.compile(r"^pub\s+struct\s+(\w+)", re.MULTILINE) | ||
| EXPORT_ENUM_RE = re.compile(r"^pub\s+enum\s+(\w+)", re.MULTILINE) | ||
| EXPORT_TRAIT_RE = re.compile(r"^pub\s+trait\s+(\w+)", re.MULTILINE) | ||
| EXPORT_CONST_RE = re.compile(r"^pub\s+const\s+(\w+)", re.MULTILINE) |
There was a problem hiding this comment.
Avoid treating
fn as a const export
For valid public const functions such as pub const fn new() -> Self, this regex captures the literal token fn; the function regex does not accept const, so the resulting component advertises a phantom export named fn and omits new. Distinguish pub const NAME declarations from pub const fn NAME and extract the latter as a function.
Useful? React with 👍 / 👎.
|
|
||
| EXCLUDE_SUFFIXES = (".g.dart", ".freezed.dart", "_test.dart") | ||
|
|
||
| EXPORT_CLASS_RE = re.compile(r"^(?:abstract\s+)?class\s+(\w+)", re.MULTILINE) |
There was a problem hiding this comment.
Recognize Dart 3 class modifiers
Public Dart declarations using supported modifiers such as final class, base class, sealed class, or interface class do not match this expression. If such a file has no other recognized declaration, the adapter drops the component entirely, which is common in Dart 3 codebases; accept the class modifiers before class while retaining the existing underscore privacy filter.
Useful? React with 👍 / 👎.
Item 7 remainder -- #10 closed the TypeScript/Python adapter work but scoped these three out on purpose. Regex-based, same philosophy as the existing adapters (not a full parse, limitations documented in coverage_text). Confirmed against real source in the portfolio before writing any pattern (Quantitativo MEV bot, statum-fi, HZ02 token, Rodax Flutter app) -- not guessed syntax. - RustAdapter: top-level pub fn/struct/enum/trait/const/static/type, plus public methods of impl blocks (impl Type / impl Trait for Type) -- the same "capability lives in a member block, not a top-level export" shape that TypeScript needed a follow-up fix for (issue #35), handled here from day one. pub(crate)/pub(super) excluded implicitly (no space between pub and the paren, so the regex never matches them). - SolidityAdapter: contract/interface/library names, plus event names and public/external function names inside them. Solidity puts the visibility modifier *after* the parameter list, not before the function name (unlike TS/Rust), and signatures commonly wrap across lines (seen in the real HZ02.sol) -- handled by joining a bounded window of lines from the function match up to its first '{' or ';' and checking visibility on the joined text. Skips lib/out/cache/artifacts/ typechain-types (Foundry/Hardhat vendored deps and build output, not in core.py's generic exclude list) and *.t.sol/*.s.sol (tests/scripts). - DartAdapter: top-level class/abstract class/mixin/enum/typedef, plus a best-effort match of methods (a lazy prefix skips the return type, including nested generics, without parsing it). Members of a class/ mixin whose own name starts with '_' are skipped entirely, not just filtered by their own name -- confirmed against the real, ubiquitous `_FooState extends State<Foo>` pattern every StatefulWidget uses, where a public-looking `build()` override is framework-invoked, never citable capability (a real difference from TypeScript's class-method handling, where a non-exported class can still be reached through an exported instance -- Dart has no equivalent escape hatch once the type itself is private). Found and fixed during testing: the lazy return-type prefix swallows leading whitespace by design, which meant an unguarded version matched control-flow statements nested deep inside method bodies (`if (...)` reads exactly like name-then-paren too) -- fixed with a `(?=\S)` guard requiring the actual member/function line to start immediately, no swallowed indentation. Known gap, disclosed in coverage_text not hidden: generic methods (`name<T>(...)`) aren't extracted -- confirmed against the real api_client.dart, all 4 HTTP-verb methods use this exact generic shape and are missed, only the non-generic setAccessToken is caught. Wiring: registered in scan/adapters/__init__.py ADAPTERS; cli.py's two --language choices lists (scan run, verify) updated -- they're hardcoded separately from the ADAPTERS dict, a pre-existing gap, not something new introduced here. Also fixed portfolio.py's LANGUAGE_MARKERS: Anchor.toml was labeled "Solidity/Anchor", which is wrong -- Anchor.toml marks Solana's Rust-based Anchor framework, not Solidity (an EVM/Ethereum language). Now "Rust/Anchor". Not in scope: onboarding Quantitativo/statum-fi/the Flutter apps with real .agent-architecture/project.yaml manifests -- that's portfolio rollout (Track D), a separate, bigger decision. Verification: pytest 88/88 (74 baseline + 14 new adapter tests). Also ran scan_file() directly against real files (not just synthetic fixtures): Quantitativo's engine.rs (5/5 real pub items captured correctly, including impl-block methods), Executor.sol and HZ02.sol (perfect on both, including the multi-line mintFromBatch signature), Rodax's api_client.dart (correctly conservative -- ApiClient + setAccessToken, generic methods correctly not matched rather than mismatched).
11b8fac to
268521f
Compare
Closes #43.
Item 7 remainder — #10 closed the TypeScript/Python adapter work but scoped Rust/Solidity/Dart out on purpose. Regex-based, same philosophy as the existing adapters (not a full parse, limitations documented in
coverage_text). Confirmed against real source in the portfolio before writing any pattern (Quantitativo's MEV bot, statum-fi, the HZ02 token, Rodax's Flutter app) — not guessed syntax.RustAdapterTop-level
pub fn/struct/enum/trait/const/static/type, plus public methods ofimpl Type/impl Trait for Typeblocks — the same "capability lives in a member block, not a top-level export" shape that TypeScript needed a follow-up fix for (issue #35), handled here from day one.pub(crate)/pub(super)excluded implicitly (no space betweenpuband the paren, so the regex never matches them).SolidityAdaptercontract/interface/librarynames, pluseventnames and public/externalfunctionnames inside them. Solidity puts the visibility modifier after the parameter list, not before the function name (unlike TS/Rust), and signatures commonly wrap across lines (seen in the realHZ02.sol) — handled by joining a bounded window of lines from thefunctionmatch up to its first{/;and checking visibility on the joined text. Skipslib/out/cache/artifacts/typechain-types(Foundry/Hardhat vendored deps and build output, not incore.py's generic exclude list) and*.t.sol/*.s.sol(tests/scripts).DartAdapterTop-level
class/abstract class/mixin/enum/typedef, plus a best-effort match of methods (a lazy prefix skips the return type, including nested generics, without parsing it). Members of a class/mixin whose own name starts with_are skipped entirely, not just filtered by their own name — confirmed against the real, ubiquitous_FooState extends State<Foo>pattern everyStatefulWidgetuses, where a public-lookingbuild()override is framework-invoked, never citable capability. This is a real difference from TypeScript's class-method handling (a non-exported TS class can still be reached through an exported instance; Dart has no equivalent escape hatch once the type itself is private).Found and fixed during testing: the lazy return-type prefix swallows leading whitespace by design, which meant an unguarded version matched control-flow statements nested deep inside method bodies (
if (...)reads exactly like name-then-paren too). Fixed with a(?=\S)guard requiring the actual member/function line to start immediately, no swallowed indentation — covered bytest_nested_indentation_inside_method_body_not_matched_as_member.Known gap, disclosed not hidden: generic methods (
name<T>(...)) aren't extracted — confirmed against the realapi_client.dart, all 4 HTTP-verb methods (get<T>,post<T>,put<T>,delete<T>) use this exact generic shape and are missed, only the non-genericsetAccessTokenis caught. Fixing this properly needs balanced-bracket matching for nested generics, not a regex tweak — flagging as a real follow-up opportunity rather than silently shipping a narrower adapter than it looks.Wiring
scan/adapters/__init__.py'sADAPTERSdict.cli.py's two--languagechoiceslists (scan run,verify) updated — they're hardcoded separately from theADAPTERSdict (pre-existing gap, not introduced here).portfolio.py'sLANGUAGE_MARKERS:Anchor.tomlwas labeled"Solidity/Anchor", which is wrong —Anchor.tomlmarks Solana's Rust-based Anchor framework, not Solidity (an EVM/Ethereum language). Now"Rust/Anchor".Not in scope
Onboarding Quantitativo/statum-fi/the Flutter apps with real
.agent-architecture/project.yamlmanifests — that's portfolio rollout (Track D), a separate, bigger decision.Verification
pytest: 88/88 (74 baseline + 14 new adapter tests).scan_file()directly against real files (not just synthetic fixtures), not just synthetic fixtures:engine.rs: 5/5 realpubitems captured correctly, including impl-block methods (DecisionEngine,ExecutionOrder,new,evaluate,set_capital).Executor.solandHZ02.sol: perfect on both, including the multi-linemintFromBatchsignature.api_client.dart: correctly conservative —ApiClient+setAccessToken, generic methods correctly not matched rather than mismatched.