feat: add CDS (SAP CAP) language support (.cds) - #1724
Open
nickels wants to merge 5 commits into
Open
Conversation
Index SAP CAP CDS models with a vendored cap-js-community/tree-sitter-cds grammar (66bc383, Apache-2.0, ABI 15 rebuild with a local patch for empty annotation values and trailing element annotations). Extraction: namespace and context (namespace), service (module, members exported), entity and view (class) including projections and selects with joins, elements (field) with key/virtual decorators and nested structures, type (type_alias or enum) with enum members, aspect (interface), event (struct), annotation definitions, unbound actions and functions (function), bound actions (method), using imports with alias maps, extend members rooted at the extended artifact, annotate targets, annotations as decorators and doc comments. Dotted definition names split into scope and leaf so the dot-normalized qualifiedName is the CDS fully qualified name. References: includes (extends), association and composition targets, non-builtin element and parameter types, projection and select sources, redirected-to targets, extend and annotate targets, and each using artifact.
Language detection plus a CDS Extraction block: namespaces and qualified names, artifact kinds, elements and enums, services and actions, annotations and doc comments, using aliases, references, extend and annotate, dotted definition names, per-file state, and a file the grammar trips on.
Add a terminal CDS branch to matchReference: candidates by last segment (or the full dotted name for namespaces), compared dot-normalized against the caller's scope chain from innermost to the file level, with a unique bare-name fallback and no fuzzy fallthrough. Relative using-from specifiers resolve to model files through ['.cds', '/index.cds']; package specifiers stay external. Refs from other languages never land on CDS nodes. Named symbol flow matches dotted CDS names against the namespace-as-one-segment qualifiedName spelling.
Unit tests for the CDS matcher (scoped lookup, alias FQN, self-exclusion, ambiguity, namespace aliases, action targets, language isolation) and the using-from path resolution, plus an end-to-end test that indexes a db/srv/app CAP project and checks every edge kind and the unresolved-by-design list.
README table row and logo, CHANGELOG entry, framework-coverage and kernel migration rows, and three CAP repos with cross-file questions in the agent-eval corpus.
nickels
marked this pull request as ready for review
September 7, 2026 06:52
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #648 (the language support tracking issue, which consolidates individual requests). No separate CDS request issue exists.
Indexes SAP CAP CDS models (
.cds) the way they are written: namespaces and contexts, services, entities and views, elements with their associations and compositions, types and enums, aspects, events, actions and functions (bound and unbound), plususingimports with alias expansion,extendandannotatedirectives, and annotations kept as decorators (@readonly,@requires,@restrict,@path,@UI.*, ...). Service projections link to the db entities they project, includes link to the aspects they pull in, associations link to their targets, and relativeusing ... frompaths link files.This is a from-scratch extractor on current
main, modelled on #1685 (Elixir): definitions are dispatched invisitNodebecause CDS definitions carry their elements as direct children, and a small CDS branch in the name matcher resolves references by CDS scoping rules (service scope, then enclosing context and namespace, then fully qualified) using the dot-normalized qualified name.What it extracts
namespace/context(namespace),service(module, members marked exported)entity/view(class) includingas projection onandas select fromwith join sourceskey/virtualdecorators, nested structures, enum memberstype(type_alias or enum),aspect(interface),event(struct),annotationdefinitionsaction/function(function), boundactions { }(method)using { a.b.C as D } from '../db/schema'alias maps, per-artifact references and file import edgesextend X with { ... }elements and actions rooted at the extended definition,annotate X withreferences/** */,//) as docstringsGrammar
Vendored cap-js-community/tree-sitter-cds @ 66bc383 (v2.0.0, Apache-2.0) with a small local patch (
docs/grammars/tree-sitter-cds.patch): empty[]/{}annotation values and annotations afterdefault/not null, which broke 9 of 247.cdsfiles across 11 real CAP repos. Built with tree-sitter-cli 0.25.10 (generate+build --wasm --docker, emsdk 4.0.4, ABI 15); all 60 upstream corpus tests plus 2 new ones pass on the regenerated parser, and the patched wasm parses all 247 corpus files with no ERROR node. SAP archived the grammar repository in June 2026 and it describes itself as a highlighting grammar rather than a 100 percent compatible parser, so provenance, rebuild steps, parse health and the remaining known gaps live indocs/grammars/tree-sitter-cds.md.tree-sitter-wasmsdoes not ship it.Extraction (real repos)
Unit tests: CDS block in
__tests__/extraction.test.tsplus__tests__/cds-resolution.test.ts(scoped lookup, alias FQN, self-exclusion, ambiguity, import paths) and__tests__/cds-cross-file.test.ts(end-to-end db/srv/app project).Retrieval A/B
Two with/without runs (
scripts/agent-eval/run-all.sh, Sonnet, effort high, n=1 per arm), one per corpus question on the Small and Medium repos:Both arms reached the right files and the right answer every time. The with-arm never called codegraph: the MCP server attached (1 tool exposed) but Sonnet grepped
LROPODataService/AdminServiceand read the two or three.cdsfiles that hold the whole answer. CDS models are small and grep-friendly, so a retrieval win is not the merge bar here; extraction quality (the table above, the cross-file edges, and the three flow probes below) is.Flow probes over the index (references / implements edges, up to 4 hops): fiori
LROPODataService::RootEntities -> sap.fe.showcase::RootEntities -> (includes) rootBasis -> (criticality) -> sap.common::Criticalityconnects; btpAdminService::Members -> susaas::db::Members -> (user) -> susaas::db::Users -> (role) -> susaas::db::Rolesconnects (context susaas.dbis stored as scopesusaasplusdb; dot-normalized it is the CDS name); bookshop-demoAdminService::Books -> my.bookshop::Books -> (genre) -> my.bookshop::Genresconnects (itsmanagedandsap.common.CodeListincludes come from@sap/cds/commonand stay unresolved by design).Follow-ups (not in this PR)
gen/build output ofcds buildis not ignored by default (it can duplicate.cdssources)@UIannotation semantics andsrv/*.jshandler wiring (srv.on('READ', 'Books', ...)) as cross-language edgesWHEN/ branch-guard rules do not apply (declarative language)Re-index CDS projects after upgrading.