Skip to content

feat: discover and parse CCXT declarations (Task 6)#9

Merged
e-fu merged 2 commits into
developmentfrom
feat/task-6-declarations
May 17, 2026
Merged

feat: discover and parse CCXT declarations (Task 6)#9
e-fu merged 2 commits into
developmentfrom
feat/task-6-declarations

Conversation

@e-fu
Copy link
Copy Markdown
Contributor

@e-fu e-fu commented May 17, 2026

Summary

Compile-time parser that turns CCXT's TypeScript declarations into rich per-method terms (name, params, return type, owning surface, overrides) for the Phase 2 macro layer to consume. Completes Task 6 (v0_1 milestone, macros bundle).

  • New CcxtOcx.Declarations facade + CcxtOcx.Declarations.Compile parser. Walks js/src/base/Exchange.d.ts, per-exchange *.d.ts, and pro/*.d.ts with OXC.parse/2 + OXC.collect/2, classifying methods by :base, :exchange, or :pro surface and capturing per-exchange overrides.
  • Filter ownership (verb-prefix allowlist, internal-prefix denylist, exact-name denylist, bare-name trade-plane allowlist) centralized here. CcxtOcx.BundleSurface.Compile now delegates to Declarations.Compile.public_unified_method?/1 so the "what gets a defunified wrapper" decision lives in one place.
  • Overrides map keyed by "surface:exchange_id" so a method declared in both js/src/<id>.d.ts and js/src/pro/<id>.d.ts (e.g. kucoinfutures.fetchBidsAsks) keeps both override entries instead of one silently overwriting the other.
  • Loud layout guard raises with actionable instructions if CCXT bumps and the three smoke methods (fetchTicker, createOrder, watchTicker) disappear from the base surface.
  • @external_resource registered for every discovered base/exchange/pro .d.ts so mix npm.update ccxt triggers a recompile of the facade.

Test plan

  • mix compile --warnings-as-errors clean
  • mix format --check-formatted clean
  • mix credo --strict clean (only expected TODO tags)
  • mix test.json --quiet — 165/165 offline tests pass
  • mix test.json --quiet --include integration test/ccxt_ocx/declarations_test.exs — 12/12 integration tests pass against real CCXT .d.ts
  • mix sobelow --mark-skip-all regenerated for line-fingerprint drift

Summary by CodeRabbit

  • New Features

    • Added compile-time declaration parsing and a public facade to expose unified method metadata for future macro-driven generation.
  • Documentation

    • Updated changelog, roadmap and design notes to mark Phase 2 Task 6 complete and describe the new parsing surface.
  • Refactor

    • Centralized public-method filtering logic for consistency across compilation steps.
  • Tests

    • Added unit and integration tests covering parsing, type rendering, and validation.
  • Chores

    • Updated security-scan exceptions to accommodate the new parsing/runtime patterns.

Review Change Stack

Copilot AI review requested due to automatic review settings May 17, 2026 12:25
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 17, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6743149e-d10f-460e-8e94-6fdca158ba64

📥 Commits

Reviewing files that changed from the base of the PR and between dcdf7b3 and 49e6ecd.

📒 Files selected for processing (2)
  • lib/ccxt_ocx/declarations/compile.ex
  • test/ccxt_ocx/declarations_test.exs
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/ccxt_ocx/declarations_test.exs
  • lib/ccxt_ocx/declarations/compile.ex

📝 Walkthrough

Walkthrough

This PR completes Phase 2 Task 6 by introducing the CcxtOcx.Declarations module ecosystem to parse CCXT TypeScript declaration files at compile time, extract public method metadata with surface classification, and refactor unified-method filtering logic from BundleSurface.Compile into a centralized, reusable location.

Changes

CCXT Declaration Parsing

Layer / File(s) Summary
Declaration Parsing Core Implementation
lib/ccxt_ocx/declarations/compile.ex
CcxtOcx.Declarations.Compile provides OXC-driven parsing of base, exchange, and pro .d.ts files; filters methods via verb-prefix, internal-prefix, and denylist predicates; extracts parameter and return-type signatures; recursively renders TypeScript AST nodes to Elixir-friendly strings; groups methods by name with overrides keyed by surface:exchange_id; and enforces compile-time layout guards that verify smoke-test methods exist and originate from base surface.
Public Declarations Facade & Recompilation Tracking
lib/ccxt_ocx/declarations.ex
CcxtOcx.Declarations wraps Compile module as the public compile-time API, registers @external_resource tracking for all discovered declaration sources to trigger recompilation on file changes, and exposes parse_unified_surface/0, public_unified_method?/1, and base_dts_path/0 as delegating public functions with full documentation and typespecs.
BundleSurface Refactoring
lib/ccxt_ocx/bundle_surface/compile.ex
Removes the local public_unified_method?/1 predicate and refactors extract_unified_methods/1 to delegate filtering to the centralized Declarations.Compile.public_unified_method?/1, updates module documentation to reflect ownership transfer, and adds required module alias.
Test Suite
test/ccxt_ocx/declarations_test.exs
Comprehensive test coverage including unit tests for public_unified_method?/1 (verb allowlist, internal/denylist rejection), render_type/1 (primitives, type references, generics, unknown fallback), integration tests validating smoke-method extraction and surface classification across base/exchange/pro, and path helper tests confirming glob expansions.
Documentation & Roadmap Updates
.sobelow-skips, CHANGELOG.md, CLAUDE.md, ROADMAP.md, roadmap/data.json, roadmap/tasks.toml
Adds Sobelow security exceptions for OXC-driven file I/O, documents Task 6 completion in CHANGELOG, updates macro-planning reference in CLAUDE.md, marks Task 6 as complete in ROADMAP with status indicators, and records completion metadata and timestamp in roadmap data/task files.

Sequence Diagram

sequenceDiagram
  participant Compile as CcxtOcx.Declarations.Compile
  participant DeclarationsAPI as CcxtOcx.Declarations.parse_unified_surface/0
  participant OXC as OXC.parse/2
  participant MethodFilter as CcxtOcx.Declarations.Compile.public_unified_method?/1
  participant LayoutGuard as assert_required_methods!/1
  DeclarationsAPI->>OXC: read/parse base Exchange.d.ts
  DeclarationsAPI->>OXC: read/parse exchange *.d.ts (glob)
  DeclarationsAPI->>OXC: read/parse pro/*.d.ts (glob)
  OXC-->>DeclarationsAPI: AST nodes
  DeclarationsAPI->>MethodFilter: filter method names
  MethodFilter-->>DeclarationsAPI: included methods
  DeclarationsAPI->>LayoutGuard: validate smoke methods and primaries
  LayoutGuard-->>DeclarationsAPI: pass or raise error
  DeclarationsAPI-->>Compile: return sorted method terms with overrides
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • ZenHive/ccxt_ocx#5: Earlier refactor that moved public_unified_method?/1 predicate to a centralized location, overlapping with this PR's delegation and Sobelow adjustments.

Poem

🐰 I hopped through .d.ts and code so wide,

OXC gave ASTs, methods unified,
Smoke methods checked, overrides aligned,
Docs and tests in tidy lines—
Task six done, the compile-time paths abide.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: discover and parse CCXT declarations (Task 6)' clearly and concisely describes the primary change: adding CCXT declaration discovery and parsing functionality, with reference to the completed roadmap task.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/task-6-declarations

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a compile-time CCXT TypeScript declaration parser that will feed the Phase 2 macro-generation layer with unified method metadata.

Changes:

  • Introduces CcxtOcx.Declarations and CcxtOcx.Declarations.Compile to discover, parse, filter, and classify CCXT .d.ts method declarations.
  • Centralizes unified-method filtering and updates BundleSurface.Compile to delegate to it.
  • Adds tests and updates roadmap/changelog/docs to mark Task 6 complete.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
lib/ccxt_ocx/declarations/compile.ex Implements declaration discovery, parsing, type rendering, filtering, overrides, and layout guards.
lib/ccxt_ocx/declarations.ex Adds public facade and external resource tracking for declaration files.
lib/ccxt_ocx/bundle_surface/compile.ex Delegates unified method filtering to the new declarations module.
test/ccxt_ocx/declarations_test.exs Adds unit and integration coverage for filtering, type rendering, parsing, and path helpers.
ROADMAP.md Marks Task 6 as complete.
roadmap/tasks.toml Marks Task 6 done and records implementation metadata.
roadmap/data.json Mirrors Task 6 completion metadata.
CHANGELOG.md Documents the new declaration parser under Unreleased.
.sobelow-skips Updates Sobelow skip fingerprints for changed/new file-read locations.
CLAUDE.md Updates project guidance to mention the new declarations data source.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/ccxt_ocx/declarations/compile.ex Outdated
Comment on lines +353 to +381
missing = Enum.reject(@required_smoke_methods, &MapSet.member?(present, &1))

if missing != [] do
raise """
CCXT declaration layout changed — required unified methods disappeared.

Missing from :base surface (or filtered out):
#{inspect(missing)}

Expected them in:
#{base_dts_path()}

This is a deliberate loud failure (Task 6 acceptance).
After a `mix npm.update ccxt`, review the diff and either:
- pin a known-good version in package.json, or
- run `mix ccxt.verify_bundle --accept` (after human review).

If the methods genuinely moved to a different .d.ts, update the discovery
globs in Declarations.Compile.
"""
end

# Also assert that at least one of them truly came from the base Exchange.d.ts
base_sources =
terms
|> Enum.filter(&(&1.name in @required_smoke_methods))
|> Enum.map(& &1.primary.source)

if !Enum.any?(base_sources, &String.ends_with?(&1, "Exchange.d.ts")) do
Comment thread test/ccxt_ocx/declarations_test.exs Outdated
Comment on lines +90 to +93
|> Enum.flat_map(fn t -> [t.primary.surface] ++ Map.keys(t.overrides) end)
|> Enum.uniq()

assert :base in all_surfaces
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/ccxt_ocx/declarations/compile.ex`:
- Around line 353-386: The current validation only ensures at least one of
`@required_smoke_methods` has a primary source ending with "Exchange.d.ts" (via
base_sources and Enum.any?), which can miss other required names; change the
check to verify each required smoke method in terms has primary.source ending in
"Exchange.d.ts" and collect any names that fail this per-method check, then
raise a clear error listing those method names (use `@required_smoke_methods`,
terms, each term.primary.source and Exchange.d.ts in the message) so the failure
surfaces which specific required methods lost their base :base primary surface.

In `@test/ccxt_ocx/declarations_test.exs`:
- Around line 84-97: The test "distinguishes base / exchange / pro surfaces and
populates overrides" calls Declarations.parse_unified_surface() and builds
all_surfaces from terms but never asserts that :pro is present; update the
assertion logic so it explicitly checks that :pro is included in all_surfaces
(the variable built from terms and Map.keys(t.overrides))—for example add an
assertion that :pro in all_surfaces or assert Enum.member?(all_surfaces, :pro)
to ensure pro-surface participation is enforced by the test.
- Around line 107-109: The two brittle assertions using a magic threshold should
be made robust: replace the hard-coded "> 50" checks on
Compile.exchange_dts_paths() and Compile.pro_dts_paths() with
existence/non-empty checks (e.g., assert length(Compile.exchange_dts_paths()) >
0 or assert Enum.any?(Compile.exchange_dts_paths())) or make the minimum
threshold configurable via an env var; update the test to use
Compile.exchange_dts_paths and Compile.pro_dts_paths references so it only
asserts the lists are non-empty (or uses a configurable threshold) rather than a
fixed 50-file magic number.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5dc6bd98-8055-4cd5-88e7-e023e442ba4b

📥 Commits

Reviewing files that changed from the base of the PR and between 8510bde and dcdf7b3.

📒 Files selected for processing (10)
  • .sobelow-skips
  • CHANGELOG.md
  • CLAUDE.md
  • ROADMAP.md
  • lib/ccxt_ocx/bundle_surface/compile.ex
  • lib/ccxt_ocx/declarations.ex
  • lib/ccxt_ocx/declarations/compile.ex
  • roadmap/data.json
  • roadmap/tasks.toml
  • test/ccxt_ocx/declarations_test.exs

Comment thread lib/ccxt_ocx/declarations/compile.ex
Comment thread test/ccxt_ocx/declarations_test.exs
Comment thread test/ccxt_ocx/declarations_test.exs
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dcdf7b3eb7

ℹ️ 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".

Comment thread lib/ccxt_ocx/declarations/compile.ex Outdated
|> Enum.filter(&(&1.name in @required_smoke_methods))
|> Enum.map(& &1.primary.source)

if !Enum.any?(base_sources, &String.ends_with?(&1, "Exchange.d.ts")) do
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require every smoke method to stay on the base surface

When a future CCXT update moves only one required smoke method (for example createOrder) out of Exchange.d.ts while another required method remains there, this Enum.any? still lets the layout guard pass. In that case primary for the moved method falls back to an arbitrary exchange/pro declaration, so the parser no longer fails loudly even though the base unified contract changed; the guard should verify each required smoke method has a base Exchange.d.ts primary, not just that at least one does.

Useful? React with 👍 / 👎.

…erride surfaces

Layout guard previously used Enum.any?, so it would have stayed silent if
e.g. createOrder moved off Exchange.d.ts while fetchTicker stayed — exactly
the drift class Task 6 acceptance requires the guard to catch. Now checks
each of fetchTicker/createOrder/watchTicker is primary :base from
Exchange.d.ts and lists every offender in the raised message.

Integration test that 'distinguishes base / exchange / pro surfaces' was
flattening Map.keys(overrides) (strings like "exchange:binance"), so the
:exchange / :pro atoms never appeared in all_surfaces — only :base was
ever asserted. Now reads surface atoms off Map.values(overrides) and
asserts :exchange and :pro both contribute, catching surface-classification
regressions explicitly.

Reviewed by: CodeRabbit, Copilot, Codex GitHub bot (3-bot convergence on
the layout-guard finding).
@e-fu e-fu merged commit 32623e7 into development May 17, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants