@abapify/acds
A parser for ABAP CDSABAP CDSThe modelling layer of ABAP Cloud — view entities, projections and annotations defined above database tables, delivered with the platform rather than installed.sap official, abap DDL source — tokenizer, parser and a typed AST covering tables, structures, simple types, service definitions and metadata extensions.
Built on Chevrotain with error recovery, so partial or in-progress source still yields a tree. It is the piece anything that wants to analyse ABAP CDSABAP CDSThe modelling layer of ABAP Cloud — view entities, projections and annotations defined above database tables, delivered with the platform rather than installed.sap official, abap without a system needs first.
Facts
Where it sits
Who is behind it
In the atlas: maintains 9@abapifymaintainerOpenHandsContributes to this
In the atlas: contributes to 1@openhands-agentPetr PlenkovContributes to this
In the atlas: contributes to 13@ThePlenkov2 contributors
What it declares
Every artifact
- Type
- Package
- Origin
- Independently maintained
- Runtime
- build time
As a package
- Where it runs
- does not say
- Distributed through
- does not say
Connections
Catching problems in code before execution
Download
Install
npm add @abapify/acdsDerived from the package name. No recipe recorded; the README has the configuration.
README
quoted from abapify/adt-cli under MIT, read@abapify/acds
ABAP CDS source parser — tokenizer, parser, and typed AST for DDL-based ABAP source types.
Overview
Parses .acds (ABAP CDS DDL) source code into a fully typed Abstract Syntax Tree. Built on Chevrotain for fast, error-recovering parsing.
Supported Definitions
| CDS Construct | AST Node | Example |
|---|---|---|
| Table | TableDefinition | define table [entity] ztable { ... } |
| Root table ent. | TableDefinition | define root table entity ztable { ... } |
| Structure | StructureDefinition | define structure zstruct { ... } |
| Simple type | SimpleTypeDefinition | define type ztype : abap.char(10); |
| View entity | ViewEntityDefinition | define [root] view entity zv as select ... |
| Legacy view | ViewEntityDefinition | define view zv as select ... (legacy) |
| Abstract entity | AbstractEntityDefinition | define abstract entity zae { ... } |
| Custom entity | CustomEntityDefinition | define custom entity zce { ... } |
| External entity | ExternalEntityDefinition | define external entity zee { ... } with federated data provided at runtime; |
| Table function | TableFunctionDefinition | define table function ztf returns { ... } |
| Scalar function | ScalarFunctionDefinition | define scalar function zsf ... |
| Hierarchy | HierarchyDefinition | define hierarchy zh as parent child hierarchy(...) { ... } |
| Aspect | AspectDefinition | define aspect za { ... } |
| Annotation | AnnotationDefinition | define annotation za: Boolean; |
| Access policy | AccessPolicyDefinition | define accesspolicy zap { ... } |
| Service | ServiceDefinition | define service zsvc { ... } |
| Extension | ExtensionDefinition | extend view entity zv with { ... } |
| Metadata ext. | MetadataExtension | annotate entity ZView with { ... } |
| Role (DCL) | RoleDefinition | define role zr { grant select ... } |
Parser Features
- Error recovery — returns partial AST + structured errors on invalid input
- Full annotation support — strings, enums, booleans, numbers, arrays, objects
- Built-in types —
abap.char(10),abap.dec(11,2),abap.dats, etc. - Named types — data element and qualified name references
- Include directives —
include <structure>with optional suffix - Comments — line (
//,--) and block (/* */) comments are skipped - Case-insensitive keywords —
DEFINE VIEW ENTITYanddefine view entityboth parse; identifiers keep their original spelling - FROM clause — join chains, parameterized sources, FROM associations
- View flavours —
define view entity <name>and the legacydefine view <name> - Projection elements — paths, calls (
coalesce(a, b),sum(x)) andcast(x as type [preserving type])
Installation
bun add @abapify/acds
Quick Start
import { parse } from '@abapify/acds';
const result = parse(`
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
define table ztable {
key mandt : abap.clnt not null;
key field1 : abap.char(10) not null;
field2 : some_data_element;
}
`);
if (result.errors.length === 0) {
const table = result.ast.definitions[0]; // TableDefinition
console.log(table.kind); // 'table'
console.log(table.name); // 'ztable'
console.log(table.members); // [FieldDefinition, FieldDefinition, ...]
console.log(table.annotations); // [Annotation, Annotation]
}
API
parse(source: string): ParseResult
Parses a CDS source string through the full pipeline: tokenize → parse → visit.
interface ParseResult {
/** The parsed AST (may be partial if there are errors) */
ast: CdsSourceFile;
/** Lexing and parsing errors */
errors: CdsParseError[];
}
AST Types
Root
interface CdsSourceFile {
definitions: CdsDefinition[];
}
type CdsDefinition =
| TableDefinition
| StructureDefinition
| SimpleTypeDefinition
| ViewEntityDefinition
| AbstractEntityDefinition
| CustomEntityDefinition
| ExternalEntityDefinition
| TableFunctionDefinition
| ScalarFunctionDefinition
| HierarchyDefinition
| AspectDefinition
| AnnotationDefinition
| AccessPolicyDefinition
| ServiceDefinition
| ExtensionDefinition
| MetadataExtension
| RoleDefinition;
Definitions
interface TableDefinition {
kind: 'table';
name: string;
annotations: Annotation[];
members: TableMember[]; // FieldDefinition | IncludeDirective
}
interface StructureDefinition {
kind: 'structure';
name: string;
annotations: Annotation[];
members: TableMember[];
}
interface SimpleTypeDefinition {
kind: 'simpleType';
name: string;
annotations: Annotation[];
type: TypeRef;
}
interface ServiceDefinition {
kind: 'service';
name: string;
annotations: Annotation[];
exposes: ExposeStatement[];
}
interface MetadataExtension {
kind: 'metadataExtension';
entity: string;
annotations: Annotation[];
elements: AnnotatedElement[];
}
Fields & Types
interface FieldDefinition {
annotations: Annotation[];
name: string;
type: TypeRef;
isKey: boolean;
notNull: boolean;
}
type TypeRef = BuiltinTypeRef | NamedTypeRef;
// abap.char(10), abap.dec(11,2)
interface BuiltinTypeRef {
kind: 'builtin';
name: string;
length?: number;
decimals?: number;
}
// Data element or qualified name
interface NamedTypeRef {
kind: 'named';
name: string;
}
Annotations
interface Annotation {
key: string;
value: AnnotationValue;
}
type AnnotationValue =
| { kind: 'string'; value: string }
| { kind: 'enum'; value: string } // #TRANSPARENT → 'TRANSPARENT'
| { kind: 'boolean'; value: boolean }
| { kind: 'number'; value: number }
| { kind: 'array'; items: AnnotationValue[] }
| { kind: 'object'; properties: AnnotationProperty[] };
FROM clause (view entities)
interface ViewEntityDefinition {
kind: 'viewEntity';
name: string;
annotations: Annotation[];
legacy?: boolean; // true for the legacy `define view <name>` syntax
root?: boolean; // `define root view entity`
writable?: boolean; // `define writable view entity`
providerContract?: string; // `provider contract transactional_query`
sourceKind: DataSourceKind; // 'select' | 'projection'
distinct?: boolean; // `select distinct`
source: DataSource; // the root data source
joins: JoinClause[]; // ordered join chain — empty when there are no joins
fromAssociations?: AssociationDeclaration[]; // associations of the FROM region
aspectBindings?: AspectBinding[]; // `bind aspect` bindings
parameters: ParameterDefinition[];
members: ViewMember[];
where?: Expression;
groupBy?: string[];
having?: Expression;
setOperations?: SetOperation[]; // union/intersect/except branches
}
interface DataSource {
name: string;
alias?: string;
parameters?: DataSourceParameter[]; // parameterized source
}
interface DataSourceParameter {
name: string; // e.g. 'P_StartDate'
value: string; // raw binding: ':P_Key1StartDate', '$session.client', "'X'"
}
type JoinType = 'inner' | 'leftOuter' | 'rightOuter' | 'fullOuter' | 'cross';
// Conditioned joins always carry an ON condition — the grammar enforces it.
interface ConditionedJoinClause {
kind: 'join';
joinType: 'inner' | 'leftOuter' | 'rightOuter' | 'fullOuter';
source: JoinSource; // DataSource | JoinGroup
on: Expression; // the ON condition (opaque)
cardinality?: WordCardinality; // `many to one join` / `to one join`
}
// A cross join never carries an ON condition.
interface CrossJoinClause {
kind: 'join';
joinType: 'cross';
source: JoinSource;
}
type JoinClause = ConditionedJoinClause | CrossJoinClause;
// A join source is either a plain data source or a parenthesized group.
type JoinSource = DataSource | JoinGroup;
// `join (A join B on …) on …` — the group acts as a single join source.
interface JoinGroup {
kind: 'joinGroup';
source: JoinSource; // nested — may itself be a group
joins: JoinClause[]; // the join chain inside the parentheses
}
Supported join spellings (normalized to JoinType):
| spelling | joinType | Notes |
|---|---|---|
JOIN | inner | |
INNER JOIN | inner | |
LEFT JOIN | leftOuter | OUTER is optional |
LEFT OUTER JOIN | leftOuter | |
RIGHT JOIN | rightOuter | OUTER is optional |
RIGHT OUTER JOIN | rightOuter | |
FULL JOIN | fullOuter | OUTER is optional |
FULL OUTER JOIN | fullOuter | |
CROSS JOIN | cross | must not carry an ON condition |
The ON condition is required for inner and outer joins and not allowed
for a cross join — the grammar enforces this.
The accepted join syntax is the same for every view flavour: a CDS view entity
(define view entity) and a classic SQL view (define view) accept exactly the
same spellings. FULL [OUTER] JOIN is the SQL-standard full outer join — it is
not part of the ABAP CDS DDL join syntax, but it is supported so that HANA CDS /
CAP CDS sources (which use the standard SQL join syntax) can be read with the
same parser.
Example:
const { ast } = parse(`
define view entity ZC_Cube as select from I_Item as _Item
left outer join ZI_Other as _Other
on _Item.key = _Other.key
association [0..1] to I_Product as _Product
on $projection.Product = _Product.Product
{
key _Item.key
}
`);
const view = ast.definitions[0] as ViewEntityDefinition;
view.joins[0].joinType; // 'leftOuter'
view.joins[0].source.alias; // '_Other'
view.fromAssociations?.[0].target; // 'I_Product'
Errors
interface CdsParseError {
message: string;
line: number;
column: number;
offset: number;
length: number;
}
Architecture
Source string
→ CdsLexer (Chevrotain Lexer) tokens.ts
→ CdsParser (Chevrotain CstParser) parser.ts
→ CdsVisitor (CST → AST) visitor.ts
→ CdsSourceFile ast.ts
| Module | Responsibility |
|---|---|
tokens.ts | Token definitions (keywords, symbols, literals) |
parser.ts | Grammar rules (CST production) |
visitor.ts | CST → typed AST transformation |
ast.ts | AST node type definitions |
errors.ts | Error normalization (lex + parse) |
index.ts | parse() entry point + re-exports |
Roadmap
- ✅ DDL: tables, structures, simple types, view entities (
define [root] view entity, projection views +provider contract), legacydefine view, abstract/custom/table/external entities, table/scalar functions, hierarchies, aspects (DRAS), DDLA annotation definitions, access policies, services (SRVD), metadata extensions (DDLX),extend view/entityforms, parameters, associations, compositions - ✅ DCL: role definitions —
switchable, grant-select +where,with optional elements,combination mode and|or|redefinition,inherit,inheriting conditions - ✅ Annotations: full value grammar (strings, enums, booleans, numbers, arrays, objects, dotted keys)
- ✅ Tooling: AST walker helpers, semantic validators (
SemanticDiagnostic), grammar coverage metadata - ✅ FROM clause: join chains (
inner,left [outer],right [outer],full [outer],cross) with word cardinalities and grouped joins, parameterized sources, FROM associations, path-expression data sources (_assoc[ ... ]),bind aspect - ✅ Elements:
case … end, arithmetic, casts, calls (incl.f()), windowover (…), paths,: localized,: redirected to,distinct,where/group by/having,union [all]/intersect/except - 🔜 Expression grammar (structured
on/wheretrees — currently opaque{ source, tokens }) - 🔜 BDEF / behavior definitions (owned by epic E10)
Dependencies
chevrotain— Parser toolkit (lexer + CstParser + visitor)
History
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Features 1, Fixes 7, Other 3
Notes
🚀 Features
- acds: extend the CDS grammar to the full DDL/DCL statement set (5796ebbb)
🩹 Fixes
- acds: order Redefinition before Redefine in token list (dc1e5278)
- acds: round-2 review findings — coverage metadata, walker, docs (6e38c7e5)
- acds: address review findings — parser robustness, docs, tests (d8a3e2fd)
- acds: make the join syntax flavour-independent and support FULL OUTER JOIN (557f7c5b)
- acds: recognize keywords case-insensitively (a8c09d3e)
- acds: enforce the ON condition in the join grammar (d6df7b93)
- acds: keep FROM-region starters out of the bare source alias (37d750f1)
❤️ Thank You
- Devin @devin-ai-integration[bot]
- Rol3333 @Rol3333
- ThePlenkov @ThePlenkov
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Features 3, Fixes 3, Other 2
Notes
🚀 Features
- acds: full CDS DDL/DCL grammar + AST walker + validators — E09 (b52ec71b)
- add adt diff command and fix CDS-to-abapGit serialization (e79ecb8f)
- abapGit roundtrip - export, deploy, and structure support (29859632)
🩹 Fixes
- packages: add repository/homepage/bugs to every published package (85b29310)
- pr-103: address review comments — type safety, parity, harness, policy (d5b14cd9)
- resolve SonarQube quality gate failures (security hotspot + duplication) (8de6152a)
❤️ Thank You
- Devin @devin-ai-integration[bot]
- Petr Plenkov
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Notes
This was a version bump only for @abapify/acds to align it with other projects, there were no code changes.
Features 2, Fixes 1, Other 2
Notes
Others providing
Compare all 14 on the Static analysis page →- @abap2ui5/linter@abap2ui5/linterA command line that checks an abap2UI5 app class together with the UI5 view its builder chain produces, with no SAP system and no UI5 project.community org, abapCommand-line checker for abap2UI5 app classes and their viewsfrom ABAP
- abap2UI5 Playgroundabap2UI5 PlaygroundABAP in the editor on the left and the abap2UI5 app it builds on the right, both inside one browser tab: the framework is transpiled to JavaScript at build time and the class in the editor is compiled when Run is pressed.community org, abapIn-browser ABAP editor beside the abap2UI5 app it buildsfrom ABAP
- abapcdsgrammarabapcdsgrammarAn ANTLR4 grammar for ABAP CDS, with the lexer and parser generated from it, so CDS source can be read as a parse tree outside a system.independent, abapANTLR4 grammar, lexer and parser for ABAP CDSfrom ABAP
- abaplint-sci-clientabaplint-sci-clientThe ABAP-side client that hands objects to the abaplint Server, so the checks of abaplint surface inside SAP Code Inspector, ABAP Test Cockpit and abapGit.community org, abapABAP client surfacing abaplint checks in Code Inspector and ATCfrom ABAP
- abaplintabaplintStatic analysis for ABAP that runs outside a system on serialised source in a repository, so ABAP checks run in a pull request and in CI before the code ever reaches a system.community org, abapStatic analysis for ABAP source outside a systemfrom ABAP
- BellaBellaAn Eclipse plugin that puts Claude into ABAP Development Tools: explain, generate, rework and implement from the editor's context menu, completion as ghost text, and a chat whose tools reach the system through the developer's existing ADT logon.independent, abapEclipse plugin bringing Claude into ABAP Development Toolsfrom ABAP
- abapOpenChecksabapOpenChecksAn open-source rule pack for SAP Code Inspector and ABAP Test Cockpit, installed via abapGit and activated as a check variant.independent, abapOpen-source rule pack for SAP Code Inspector and ATCfrom ABAP
- upDOWNciupDOWNciA tool that uploads and downloads SAP Code Inspector check variants as XML files, one variant at a time or several in one ZIP file, installed through abapGit.independent, abapUploads and downloads Code Inspector check variants as XMLfrom ABAP
- abaplint-Ext-for-abapGitabaplint-Ext-for-abapGitSurfaces abaplint results inside abapGit itself, at the point where a developer is already looking.independent, abapShows abaplint results inside abapGitfrom ABAP
- ABAP remote filesystemABAP remote filesystemA Visual Studio Code extension that opens an ABAP system over ADT as an editable filesystem and exposes system tools to GitHub Copilot and external MCP clients.independent, abapVS Code extension editing ABAP systems over ADT as a filesystemfrom ABAP
- code pal for ABAPcode pal for ABAPATC and Code Inspector checks for the parts of Clean ABAP a static analyser can actually check, installed into a system with [abapGit](artifact:abapgit-abapgit) rather than delivered with it.sap official, abapATC and Code Inspector checks for Clean ABAPfrom ABAP
- Clean-Core.ioClean-Core.ioA free hosted workspace that reads one piece of custom ABAP, redraws its business process as BPMN with a line anchor on every element, grades the SAP objects it uses Level A–D and ends in a keep, rebuild, move-to-standard or retire decision.independent, abapHosted workspace redrawing custom ABAP as BPMN and grading itfrom ABAP
- ACEACEA SAP GUI tool that parses ABAP source statically to show call flow, data dependencies, control structure and code metrics such as McCabe complexity, without running the code.independent, abapSAP GUI tool for static analysis of ABAP call flow and code metricsfrom ABAP
Details
Sources
Sources are graph entities: the same page may back several entries, and an unreachable source flags every row that rests on it.
Compatibility and provenance
Contributors
History in the atlas
- Placed on data modelling because it deals in ABAP CDS definitions. Reading the capability again moved it: acds does not help you define data, it parses definitions somebody else wrote into a typed AST — which is the substrate static analysis is built on, and it lives in the adt-cli repository. The mistake surfaced when repointing a CAP package away from the ABAP capability left this one holding it alone.
- First seen.
For your agent
- Ref
artifact:abapify-acds- JSON
- /artifacts/abapify-acds.json
- MCP
- Connecting an agent