Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,22 @@ against the repos, don't guess):

| Repo | Role |
|---|---|
| [cap2UI5/cap2UI5](https://github.com/cap2UI5/cap2UI5) | the npm package `cap2ui5`: a CAP plugin that hosts upstream's transpiled runtime |
| [cap2UI5/cap2UI5](https://github.com/cap2UI5/cap2UI5) | the npm package `cap2ui5`: a CAP plugin that hosts upstream's transpiled runtime. Also the home of the decision records (`docs/adr/`) |
| [abap2UI5/abap2UI5](https://github.com/abap2UI5/abap2UI5) | the framework itself, in ABAP. Downported and transpiled, it is published as `@abap2ui5/node-runtime` |
| [cap2UI5/docs](https://github.com/cap2UI5/docs) | this site |

Both packages are on npm since 2026-09-27: `cap2ui5@0.1.0` (Node ≥ 20, peer
`@sap/cds` ≥ 9) and `@abap2ui5/node-runtime@1.145.0` (Node ≥ 22), which
`cap2ui5` pins **exactly**. The runtime package was renamed from
`@abap2ui5/runtime` before its first publish — the old name never existed on
npm, and on the site it appears only in prose that says it is the old name.
| [abap2UI5/abap2UI5](https://github.com/abap2UI5/abap2UI5) | the framework itself, in ABAP. Downported and transpiled, it is published as `@abap2ui5/node-runtime` |
| [cap2UI5/builder-abap2UI5-js](https://github.com/cap2UI5/builder-abap2UI5-js) | the ABAP→JS transpiler pipelines |

The three builder repos that generated the old CAP application
(`builder-cap2UI5`, `builder-cap2UI5-web`, `web-cap2UI5-build`) are archived.
The port's four repositories — `builder-abap2UI5-js` (the ABAP→JS transpiler
and its conformance gate), `builder-cap2UI5`, `builder-cap2UI5-web` and
`web-cap2UI5-build` (which generated the old CAP application and the
playground) — are archived or being archived, and nothing consumes their
output. Do not link them: an archived repository may be deleted. Their decision
records live in cap2UI5's `docs/adr/`.
There is no generated app, no vendored `core/`, no mirrored `app/z2ui5/webapp`.

There is **no static frontend route** and no `webapp` option either. The page
Expand Down Expand Up @@ -102,9 +106,12 @@ against the cap2UI5 repository.
## Rules

- Recommend `srv/apps/` as the place for apps — it is the plugin's default.
- The framework's own classes are **not importable**. An app imports
- The framework's own classes are **not a supported import**. Importing
`@abap2ui5/node-runtime/output/…` technically works — the package exports
`./output/*` — but it couples an app to transpiler output. A JS app imports
`cap2ui5` and nothing else; `c.raw` is the escape hatch to the transpiled
`z2ui5_if_client`.
`z2ui5_if_client`. An app that wants the framework's ABAP API (the view
builder, for one) is written in ABAP and transpiled — see the views guide.
- Measure before documenting a framework behaviour. The runtime is upstream's
ABAP running on open-abap, and not everything upstream does works here —
the user exit is discovered by a class-repository lookup in ABAP and had to
Expand Down
34 changes: 18 additions & 16 deletions HANDOVER.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ The reasoning behind all of it is in [ROADMAP.md](ROADMAP.md) §§8–25 and in
|---|---|
| upstream, the four seams + the runtime package job | [abap2UI5/abap2UI5#2772](https://github.com/abap2UI5/abap2UI5/pull/2772) merged |
| the plugin repository | [cap2UI5/cap2UI5#72](https://github.com/cap2UI5/cap2UI5/pull/72) merged, plus #75 (CI ref), #76 (the user exit), #77 (publishable package, consumer test) and #79 (`@abap2ui5/node-runtime`, startup addresses, trusted publishing) |
| the conformance gate, the prototype, the ADRs | [cap2UI5/builder-abap2UI5-js#29](https://github.com/cap2UI5/builder-abap2UI5-js/pull/29) merged |
| the conformance gate, the prototype, the ADRs | cap2UI5/builder-abap2UI5-js#29 merged (that repository is being archived; its decision records are being copied to `cap2UI5/cap2UI5:docs/adr/`) |
| this site, migrated to the plugin | [cap2UI5/docs#20](https://github.com/cap2UI5/docs/pull/20), [#21](https://github.com/cap2UI5/docs/pull/21), [#22](https://github.com/cap2UI5/docs/pull/22) merged |
| the cutover (ADR-008 steps 3–5) | `update_cap` and `build web` disabled, `generated-app-final` tagged at `595c76f`, `builder-cap2UI5`, `builder-cap2UI5-web` and `web-cap2UI5-build` archived |
| publishing | `cap2ui5@0.1.0` and `@abap2ui5/node-runtime@1.145.0` on npm; the site's quickstart runs verbatim against them (`cds init --nodejs`, `npm install cap2ui5`, `cds watch`) |
Expand All @@ -30,10 +30,12 @@ route every roundtrip gets 403. The site documents the working setup — an
extra route for the roundtrip path with `"csrfProtection": false`, safe
because abap2UI5 refuses a cross-origin POST itself
(`docs/reference/deployment.md`).
[abap2UI5/abap2UI5#2802](https://github.com/abap2UI5/abap2UI5/pull/2802) (open)
teaches the frontend the token handshake. Once it is in a release and
`cap2ui5` pins that release, drop the extra route from the deployment page and
the known limit from `guide/roadmap.md`.
[abap2UI5/abap2UI5#2802](https://github.com/abap2UI5/abap2UI5/pull/2802)
teaches the frontend the token handshake. It was merged on 2026-09-27 as
`5a1bd70`, after the 1.145.0 release, so no abap2UI5 release carries it yet.
Until `cap2ui5` pins a runtime release that does, the approuter still needs the
extra route. Then drop it from the deployment page and the known limit from
`guide/roadmap.md`.

Not exercised at all so far: a real HANA or BTP deployment. The deployment
page says so.
Expand Down Expand Up @@ -65,17 +67,17 @@ page says so.
- **Where the docs live** — `cap2UI5/docs` stays, or becomes a folder in the
plugin repo. Less urgent than it was: the rewrite is done either way, and
moving it now is a `git mv` plus the two workflows.
- **`builder-abap2UI5-js`**: still active and still running its nightly
pipeline (it mirrored and transpiled upstream `ad0a2dd` today, and its oracle
classification improved — 1,285 green methods, up from 1,272, because the
seams merged). ADR-008 archives it *after* the conformance suite is copied
where it should live. Its two red suites (`cs_event` constants, the
`upstream-units` ratchet) are `main`'s, both have a proposed patch on
[#29](https://github.com/cap2UI5/builder-abap2UI5-js/pull/29), and both are
work on a repository that is going away — worth deciding whether to fix them
at all, or to let the archive settle it.
- The four deploy keys (`ACTION_KEY_CAP`, `ACTION_KEY_APP`, `ACTION_KEY_WEB`,
`BUILT_DEPLOY_KEY`) can go from the archived repositories' secrets.
- **`builder-abap2UI5-js`** is being archived. Nothing consumes its output:
`cap2ui5` depends on `@abap2ui5/node-runtime` from npm, which abap2UI5
builds itself. The decision records that existed only there (ADR-001 to
ADR-004, ADR-006 and `transpiler-roadmap.md`) are being copied to
`cap2UI5/cap2UI5:docs/adr/`. Its two red suites (`cs_event` constants, the
`upstream-units` ratchet) had a proposed patch on its PR #29; the archive
settles them.
- `builder-cap2UI5`, `builder-cap2UI5-web` and `web-cap2UI5-build` are archived
and may be deleted — nothing links to them any more. The four deploy keys
(`ACTION_KEY_CAP`, `ACTION_KEY_APP`, `ACTION_KEY_WEB`, `BUILT_DEPLOY_KEY`) go
with them.

## What I could not do, and why

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

VitePress documentation for [**cap2UI5**](https://github.com/cap2UI5/cap2UI5) — the CAP / Node.js port of the [abap2UI5](https://github.com/abap2UI5/abap2UI5) concept. Published at **[cap2ui5.github.io/docs](https://cap2ui5.github.io/docs/)**.

A zero-install playground of the framework runs at [cap2ui5.github.io/web-cap2UI5-build](https://cap2ui5.github.io/web-cap2UI5-build/) (built by [builder-cap2UI5-web](https://github.com/cap2UI5/builder-cap2UI5-web) into [web-cap2UI5-build](https://github.com/cap2UI5/web-cap2UI5-build)).
To try it, follow the [Quickstart](https://cap2ui5.github.io/docs/guide/getting-started): a CAP project, `npm install cap2ui5`, `cds watch`.

## Develop locally

Expand Down
8 changes: 5 additions & 3 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -535,10 +535,11 @@ recommendation was wrong on the facts and was not executed.

### Where the work is tracked

[builder-abap2UI5-js `docs/adr-006-conformance.md`](https://github.com/cap2UI5/builder-abap2UI5-js/blob/main/docs/adr-006-conformance.md)
ADR-006, then in builder-abap2UI5-js and now
[`cap2UI5/cap2UI5:docs/adr/adr-006-conformance.md`](https://github.com/cap2UI5/cap2UI5/blob/main/docs/adr/adr-006-conformance.md)
— decision, the five-item worklist, and how to grow the corpus from 2 apps to 11
using upstream's own `zcl_tst_*` framework exercises.
[`docs/adr-007-repo-consolidation.md`](https://github.com/cap2UI5/builder-abap2UI5-js/blob/main/docs/adr-007-repo-consolidation.md)
ADR-007, now [`docs/adr/adr-007-repo-consolidation.md`](https://github.com/cap2UI5/cap2UI5/blob/main/docs/adr/adr-007-repo-consolidation.md)
— six repos to two, deliberately sequenced *after* the worklist: reorganising
the delivery of a broken artefact reorganises the delivery of a broken artefact.

Expand Down Expand Up @@ -871,7 +872,8 @@ by identity (its signature has no name parameter; it matches by value).

It lived only in a scratchpad, which for the most substantial part of this work
was the wrong place. It is now
[`builder-abap2UI5-js/docs/prototypes/open-abap-cap/`](https://github.com/cap2UI5/builder-abap2UI5-js/tree/main/docs/prototypes/open-abap-cap)
`builder-abap2UI5-js/docs/prototypes/open-abap-cap/` (that repository is
being archived; the prototype became cap2UI5's `plugin/` and `examples/`)
— the 548 hand-written lines plus a README with reproduction steps. The 19 MB of
transpiled framework and the webapp are gitignored, because any checkout can
rebuild them.
Expand Down
2 changes: 1 addition & 1 deletion docs/.verify-refs-ignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ app/customer-list # a hypothetical Fiori elements app, used for contrast
z2ui5_cl_app_xyz # stands for "your app class" in the interface description
my_first_app # the class the getting-started walkthrough has you write
my_app_name # stands for "your class" in the ?app_start= URL on the navigation page
zcl_my_app # stands for "the name you gave defineApp" in the why-cap2UI5 pitch
zcl_my_app # stands for "your app class": the name you gave defineApp in the why-cap2UI5 pitch, and the ABAP class on the views page — an ABAP app is registered by its transpiled class, not by defineApp
ClassName # literal placeholder in the URL-parameter description

# Upstream's frozen src/99 needs no entries any more: the plugin hosts
Expand Down
12 changes: 11 additions & 1 deletion docs/guide/ecosystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,17 @@ owns what saves time when something breaks.
| [**abap2UI5/abap2UI5**](https://github.com/abap2UI5/abap2UI5) | the framework itself: the ABAP sources and the UI5 shell. Everything cap2UI5 runs comes from here |
| [**cap2UI5/cap2UI5**](https://github.com/cap2UI5/cap2UI5) | the plugin. `plugin/` is the npm package `cap2ui5`; `examples/bookshop` is a CAP project using it; `runtime/` is a stand-in for `@abap2ui5/node-runtime` that the repository's own tests build from upstream |
| [**cap2UI5/docs**](https://github.com/cap2UI5/docs) | this site |
| [**cap2UI5/builder-abap2UI5-js**](https://github.com/cap2UI5/builder-abap2UI5-js) | the conformance gate and the ADRs that led to the current design. Historical: the build pipelines it ran are retired |

The decisions that led to the current design are in the plugin repository,
`docs/adr/` — [ADR-008](https://github.com/cap2UI5/cap2UI5/blob/main/docs/adr/adr-008-host-not-port.md)
is the one that made cap2UI5 a host rather than a port.

The four repositories of the earlier port — `builder-abap2UI5-js`, which
transpiled abap2UI5 into JavaScript, and `builder-cap2UI5`,
`builder-cap2UI5-web` and `web-cap2UI5-build`, which generated an application
and a playground from it — are archived or being archived. Nothing consumes
their output: `cap2ui5` depends on `@abap2ui5/node-runtime` from npm, which
abap2UI5 builds itself.

## The packages

Expand Down
8 changes: 5 additions & 3 deletions docs/guide/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ The frontend in runtime `1.145.0` sends no `X-CSRF-Token`, and the route
is refused with `403` until the roundtrip path gets a route of its own with
`"csrfProtection": false`. The route, and why it is safe, are on
[Deployment](../reference/deployment#the-approuter-needs-one-extra-route-today).
abap2UI5/abap2UI5#2802 (open) teaches the frontend the token handshake.
abap2UI5/abap2UI5#2802 teaches the frontend the token handshake; it is merged,
but no abap2UI5 release carries it yet.

### The facade does not cover everything

Expand Down Expand Up @@ -77,8 +78,9 @@ than by completing a table.
## What is deliberately not planned

**A cap2UI5 view builder.** Views are UI5 XML strings; a template literal is
shorter and clearer than a fluent chain in JavaScript. abap2UI5's builder is in
the runtime and reachable through `c.raw` if you want it.
shorter and clearer than a fluent chain in JavaScript. abap2UI5's builder runs
in the runtime, and an app written in ABAP can use it — see
[The ABAP view builder](./views#the-abap-view-builder).

**A second implementation of anything upstream owns.** The whole point of the
current design is that there is one implementation of the framework. A feature
Expand Down
130 changes: 127 additions & 3 deletions docs/guide/views.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,133 @@ There is no `modelUpdate()`. It existed, called a framework method documented as
## The ABAP view builder

abap2UI5 ships `z2ui5_cl_ui5_view_builder`, a fluent builder for the same XML.
It is in the runtime and ABAP apps use it — but the plugin's facade does not
expose it, because in JavaScript a template literal is shorter and clearer than
a builder chain. If you want it, it is reachable through `c.raw`.
It runs in the hosted runtime — the shipped `Z2UI5_CL_UI5_APP_HI_WORLD` is
built with it and works under cap2UI5. The facade does not expose it, and
`c.raw` does not reach it either: `z2ui5_if_client` has no reference to the
builder. In JavaScript a template literal is shorter and clearer than a builder
chain, so a JS app keeps `c.view` with `c.bind` and `c.event`.

If you want the builder, write the app in ABAP.

### An app in ABAP

A normal `z2ui5_if_app` class that uses `z2ui5_cl_ui5_view_builder`, transpiled
against the runtime the plugin hosts. The steps are the ones in the
`@abap2ui5/node-runtime` README, with three additions for a CAP project.

`abap/zcl_my_app.clas.abap` — an input and a button, built with the builder:

```abap
CLASS zcl_my_app DEFINITION PUBLIC FINAL CREATE PUBLIC.

PUBLIC SECTION.
INTERFACES z2ui5_if_app.
DATA name TYPE string.

PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.


CLASS zcl_my_app IMPLEMENTATION.

METHOD z2ui5_if_app~main.
DATA view TYPE REF TO z2ui5_cl_ui5_view_builder.

IF client->check_on_init( ) IS NOT INITIAL.

view = z2ui5_cl_ui5_view_builder=>factory(
)->ele( n = `View` ns = `mvc`
)->a( n = `xmlns` v = `sap.m`
)->a( n = `xmlns:mvc` v = `sap.ui.core.mvc`
)->a( n = `displayBlock` v = `true`
)->ele( `Page`
)->a( n = `title` v = `My ABAP app`
)->tag( `Input`
)->a( n = `value` v = client->_bind_edit( name )
)->tag( `Button`
)->a( n = `text` v = `Post`
)->a( n = `press` v = client->_event( `POST` ) ).

client->view_display( view->stringify( ) ).

ELSEIF client->check_on_event( `POST` ) IS NOT INITIAL.
client->message_toast_display( |Hello { name }| ).
ENDIF.

ENDMETHOD.

ENDCLASS.
```

Install the transpiler at exactly the version the runtime was built with:

```bash
npm install --save-dev --save-exact @abaplint/transpiler-cli@$(node -p "require('@abap2ui5/node-runtime/package.json').abap2ui5.transpiler")
```

Without `--save-exact`, npm saves a caret range, and a later install can drift
away from the runtime.

`abap_transpile.json`, with your classes in `abap/`:

```json
{
"input_folder": "abap",
"output_folder": "output",
"libs": [
{ "folder": "/node_modules/@abap2ui5/node-runtime/downport", "files": "/**/*.*" },
{ "url": "https://github.com/open-abap/open-abap-core", "folder": "/deps/open-abap-core" }
],
"write_unit_tests": false,
"options": { "ignoreSyntaxCheck": false, "addFilenames": true, "unknownTypes": "runtimeError" }
}
```

```bash
git clone --depth 1 https://github.com/open-abap/open-abap-core deps/open-abap-core
npx abap_transpile abap_transpile.json
mkdir -p srv/abap && cp output/zcl_my_app.clas.mjs srv/abap/
```

- **Clone open-abap-core once.** The transpiler uses `deps/open-abap-core`
when the folder exists; otherwise it clones into a temporary folder on every
run.
- **Copy only your own class.** `output/` also receives a full second copy of
the framework and of open-abap-core. Your class file has no imports: it
resolves everything through the runtime that is already running.
- **Put it under `srv/`.** `cds build --production` copies `srv/`, not a
top-level `output/`. Never point `output_folder` at `srv/apps`.

Then load it with one app module, `srv/apps/abap-apps.mjs`. The plugin imports
app modules after the runtime has booted, which is when a transpiled class can
register itself:

```js
await import("../abap/zcl_my_app.clas.mjs");
```

`?app_start=ZCL_MY_APP` starts it (lowercase works too), and its state survives
roundtrips like any app's. The transpile type-checks against the framework, so
a misspelled builder method fails there rather than at runtime. The startup
lines list only the apps registered with `defineApp`, not ABAP apps.

### From a JavaScript app

Reaching the transpiled class through the runtime's global,
`abap.Classes["Z2UI5_CL_UI5_VIEW_BUILDER"]`, or through the package's
`./output/*` export works, but it is awkward and unsupported: every call is
async, every result is dereferenced with `.get()`, and the app is coupled to
transpiler output.

::: warning `c.event()` does not survive the builder
In cap2ui5 0.1.0, the placeholder `c.event()` returns does not survive the
builder's XML escaping: the response then carries a raw NUL and is not valid
JSON. With the builder, the event string has to come from `c.raw`
(`z2ui5_if_client$_event`). A fix in cap2UI5 is under way.
:::

Keep template literals with `c.bind` and `c.event` in a JavaScript app.

## Next

Expand Down
11 changes: 6 additions & 5 deletions docs/guide/where-it-comes-from.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,12 @@ transpiled Node runtime, and fixed at the source for everybody.

## What is left of the port

The conformance gate that found the drift, and the measurements that made the
decision, live in
[builder-abap2UI5-js](https://github.com/cap2UI5/builder-abap2UI5-js) together
with the ADRs. The app-building pipelines are archived: nothing is generated any
more.
The decisions, and the measurements behind them, are recorded in the plugin
repository's [`docs/adr/`](https://github.com/cap2UI5/cap2UI5/tree/main/docs/adr).
The port's repositories — the transpiler with its conformance gate, and the
three that generated the application and the playground — are archived or being
archived. Nothing consumes their output any more: `cap2ui5` depends on
`@abap2ui5/node-runtime` from npm, which abap2UI5 builds itself.

## Why the ABAP names remain

Expand Down
7 changes: 4 additions & 3 deletions docs/reference/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,10 @@ gets `403`. That protection is the framework's CSRF gate, so leave
use this route.

::: info Pending upstream: abap2UI5/abap2UI5#2802
That pull request (open, not merged) teaches the frontend the standard
`X-CSRF-Token` fetch-and-send handshake. Once `cap2ui5` pins a runtime release
that carries it, the extra route can go and the generated catch-all works as
That pull request teaches the frontend the standard `X-CSRF-Token`
fetch-and-send handshake. It was merged on 2026-09-27, after the release
`cap2ui5` pins, and no abap2UI5 release carries it yet. Once `cap2ui5` pins a
runtime release that does, the extra route can go and the generated catch-all works as
it is. Until then, keep the route above.
:::

Expand Down
Loading