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
2 changes: 1 addition & 1 deletion .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

# The documented targets. verify-refs checks every path, class, app id,
# plugin option and `require("cap2ui5")` on this site against real
# plugin option and `require("@cap2ui5/cds-plugin")` on this site against real
# checkouts, so without them the run proves only that the site builds —
# it skips those checks when a checkout is missing, which is exactly the
# silent pass this job exists to prevent. Hence `check:ci` below, which
Expand Down
33 changes: 21 additions & 12 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ VitePress build. It is also what CI runs, on every pull request
- every `?app_start=` names an app something registers with `defineApp`,
- every `z2ui5_*` class or interface exists in the abap2UI5 source the hosted
runtime is transpiled from,
- every `require("cap2ui5")` or `import { … } from "cap2ui5"` **inside a code
fence** names only what the package really exports (and the port's
`abap2UI5/…` package is reported, in either form),
- every `require("@cap2ui5/cds-plugin")` or `import { … } from
"@cap2ui5/cds-plugin"` **inside a code fence** names only what the package
really exports (and two dead packages are reported, in either form: the
port's `abap2UI5/…` and the plugin's withdrawn old name `cap2ui5`),
- every `cds.cap2ui5.<option>` is an option the plugin defines,
- every `1.x.y` release number is the pinned runtime release,
- every internal anchor exists.
Expand Down Expand Up @@ -55,13 +56,19 @@ 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. Also the home of the decision records (`docs/adr/`) |
| [cap2UI5/cap2UI5](https://github.com/cap2UI5/cap2UI5) | the npm package `@cap2ui5/cds-plugin`: a CAP plugin that hosts upstream's transpiled runtime. Also the home of the decision records (`docs/adr/`) |
| [cap2UI5/samples](https://github.com/cap2UI5/samples) | the npm package `@cap2ui5/samples`: abap2UI5's samples as cap2UI5 apps, which a project adds as a (dev) dependency |
| [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
On npm since 2026-09-29: `@cap2ui5/cds-plugin@0.3.0` (Node ≥ 22, peer
`@sap/cds` ≥ 9), published by the npm organisation `cap2ui5`, and
`@cap2ui5/samples@0.1.0`. The plugin pins `@abap2ui5/node-runtime@1.145.0`
(on npm since 2026-09-27) **exactly**. Up to 0.2.0 the plugin was the unscoped
package `cap2ui5`; it is withdrawn from npm (0.2.0 never reached it), so the
site names it only as the old name. What did NOT change name: the
configuration `cds.requires.cap2ui5`, `cds add cap2ui5`, the bin
`npx cap2ui5 abap2js`, the entity `cap2ui5.Drafts` and the logger `cap2ui5`. 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.

Expand All @@ -83,7 +90,8 @@ Path conventions inside cap2UI5:

- `plugin/` — the package: `cds-plugin.js` (the route, the auth guard, the
startup lines naming each app's address), `index.cds` (the `cap2ui5.Drafts`
entity), `index.js` (what `import`/`require` of `cap2ui5` returns) and `lib/`
entity), `index.js` (what `import`/`require` of `@cap2ui5/cds-plugin`
returns) and `lib/`
(`define-app.js`, `define-exit.js`, `draft-store.js`, `hints.js`,
`runtime.js`)
- `examples/bookshop/` — a CAP project using it, with the test suite. Its apps
Expand All @@ -94,11 +102,12 @@ Path conventions inside cap2UI5:
- `docs/adr/` — the decisions, ADR-008 being the cutover

What a READER's project looks like is a different thing and must not be
confused with the above: they install `cap2ui5`, write apps in `srv/apps/`
(configurable via `cds.cap2ui5.apps`), and get the route (whose GET page
confused with the above: they install `@cap2ui5/cds-plugin`, write apps in
`srv/apps/` (configurable via `cds.cap2ui5.apps`), may add packages that bring
apps (`@cap2ui5/samples` for one), and get the route (whose GET page
embeds the UI5 frontend) and the draft entity from the plugin. A project from
`cds init --nodejs` is an ES module project, so the site's examples `import`
from `cap2ui5`; a `require` in a `.js` file there fails the whole runtime
from `@cap2ui5/cds-plugin`; a `require` in a `.js` file there fails the whole runtime
boot. `srv/`, `db/` and `app/` in the prose are
therefore **their** paths, which is why verify-refs does not check them
against the cap2UI5 repository.
Expand All @@ -109,7 +118,7 @@ against the cap2UI5 repository.
- 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
`@cap2ui5/cds-plugin` and nothing else; `c.raw` is the escape hatch to the transpiled
`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
Expand Down
5 changes: 5 additions & 0 deletions HANDOVER.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Handover — what is left

> **2026-09-29:** the plugin is published as `@cap2ui5/cds-plugin` 0.3.0 now,
> next to `@cap2ui5/samples` 0.1.0; the unscoped `cap2ui5` is withdrawn from
> npm. The site uses the new name. Below, `cap2ui5` is the name at the time
> each line was written.

Both packages are **on npm** since 2026-09-27: `cap2ui5@0.1.0` and
`@abap2ui5/node-runtime@1.145.0`, which `cap2ui5` pins exactly. The two steps
this file used to list — publish the runtime package, then point cap2UI5 at
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/)**.

To try it, follow the [Quickstart](https://cap2ui5.github.io/docs/guide/getting-started): a CAP project, `npm install cap2ui5`, `cds watch`.
To try it, follow the [Quickstart](https://cap2ui5.github.io/docs/guide/getting-started): a CAP project, `npm add @cap2ui5/cds-plugin`, `cds watch`.

## Develop locally

Expand Down
2 changes: 1 addition & 1 deletion docs/api/app-interface.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# API: `defineApp` and `t`

```js
import { defineApp, defineExit, t } from "cap2ui5";
import { defineApp, defineExit, t } from "@cap2ui5/cds-plugin";
```

`defineApp` registers a class as an app; `t` declares the field types that
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/external-odata.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ plain CAP.
```js
// srv/apps/northwind.js
import cds from "@sap/cds";
import { defineApp, t } from "cap2ui5";
import { defineApp, t } from "@cap2ui5/cds-plugin";
const { SELECT } = cds.ql;

defineApp("ZCL_NORTHWIND", class {
Expand Down
4 changes: 2 additions & 2 deletions docs/examples/hello-world.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ browser test on every CI run.

```js
// srv/apps/hello.js
import { defineApp } from "cap2ui5";
import { defineApp } from "@cap2ui5/cds-plugin";

defineApp("ZCL_JS_HELLO", class {
name = "";
Expand Down Expand Up @@ -37,7 +37,7 @@ http://localhost:4004/rest/root/z2ui5?app_start=ZCL_JS_HELLO

| | |
|---|---|
| `import { … } from "cap2ui5"` | the plugin's export surface: `defineApp`, `t`, and `defineExit` for the [user exit](../guide/user-exit) |
| `import { … } from "@cap2ui5/cds-plugin"` | the plugin's export surface: `defineApp`, `t`, and `defineExit` for the [user exit](../guide/user-exit) |
| `defineApp("ZCL_JS_HELLO", …)` | the first argument is the name **on the wire** — what `?app_start=` takes. The file name does not matter |
| `name = ""` | app state. An empty string types it as `string`, and it survives the roundtrip because the instance is written to `cap2ui5.Drafts` |
| `main(c)` | synchronous — no `async`, no `await` |
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/list.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ rather than sketched.
```js
// srv/apps/books.js
import cds from "@sap/cds";
import { defineApp, t } from "cap2ui5";
import { defineApp, t } from "@cap2ui5/cds-plugin";
const { SELECT, INSERT } = cds.ql;

defineApp("ZCL_JS_BOOKS", class {
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/selection-screen.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ closest to is [`books.js`](./list).
```js
// srv/apps/orders.js
import cds from "@sap/cds";
import { defineApp, t } from "cap2ui5";
import { defineApp, t } from "@cap2ui5/cds-plugin";
const { SELECT } = cds.ql;

defineApp("ZCL_ORDERS", class {
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/static-xml-view.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Two kinds of placeholder are in there, and the difference matters:

```js
import fs from "node:fs";
import { defineApp, t } from "cap2ui5";
import { defineApp, t } from "@cap2ui5/cds-plugin";

// read once at load, not per roundtrip; the path is relative to this file
const XML = fs.readFileSync(new URL("./views/orders.xml", import.meta.url), "utf8");
Expand Down
16 changes: 10 additions & 6 deletions docs/guide/ecosystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ 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/cap2UI5**](https://github.com/cap2UI5/cap2UI5) | the plugin. `plugin/` is the npm package `@cap2ui5/cds-plugin`; `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/samples**](https://github.com/cap2UI5/samples) | abap2UI5's samples as cap2UI5 apps, each translated from its ABAP original by `npx cap2ui5 abap2js` — the npm package `@cap2ui5/samples` |
| [**cap2UI5/docs**](https://github.com/cap2UI5/docs) | this site |

The decisions that led to the current design are in the plugin repository,
Expand All @@ -19,19 +20,22 @@ 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
their output: `@cap2ui5/cds-plugin` depends on `@abap2ui5/node-runtime` from npm, which
abap2UI5 builds itself.

## The packages

| | |
|---|---|
| `cap2ui5` | the plugin — about 640 lines of code. Mounts the route, implements the draft store over a CDS entity, turns a JS class into something the runtime can call |
| `@cap2ui5/cds-plugin` | the plugin — about 640 lines of code. Mounts the route, implements the draft store over a CDS entity, turns a JS class into something the runtime can call |
| `@abap2ui5/node-runtime` | abap2UI5: upstream's ABAP, downported and transpiled over open-abap, with the UI5 frontend embedded in the page its GET answers with — backend and frontend from one commit |
| `@cap2ui5/samples` | abap2UI5's samples as cap2UI5 apps. Optional: added to a project, they run beside its own apps — see [Apps from a package](./project-structure#apps-from-a-package) |

Both are on npm: `cap2ui5` 0.1.0 (Node ≥ 20, `@sap/cds` ≥ 9 as a peer) and
`@abap2ui5/node-runtime` 1.145.0 (Node ≥ 22), which `cap2ui5` pins exactly.
`npm install cap2ui5` installs both — see the [Quickstart](./getting-started).
All three are on npm: `@cap2ui5/cds-plugin` 0.3.0 (Node ≥ 22, `@sap/cds` ≥ 9 as a peer),
`@abap2ui5/node-runtime` 1.145.0 (Node ≥ 22), which the plugin pins exactly,
and `@cap2ui5/samples` 0.1.0. `npm add @cap2ui5/cds-plugin` installs the first two — see the
[Quickstart](./getting-started). Up to 0.2.0 the plugin was the unscoped
package `cap2ui5`, which is withdrawn from npm.

## What the plugin does and does not own

Expand Down
60 changes: 46 additions & 14 deletions docs/guide/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ already have, or to a brand new one. There is no cap2UI5 project to clone.

## Prerequisites

- **Node.js 22 or later** — `@abap2ui5/node-runtime`, which the plugin depends
on, requires it (`cap2ui5` itself says ≥ 20)
- **Node.js 22 or later** — the plugin, `@cap2ui5/cds-plugin`, and
`@abap2ui5/node-runtime`, which it depends on, both require it
- **`@sap/cds-dk`** installed globally, for the `cds` command
- Internet access — the page loads UI5 from the SAP CDN

Expand All @@ -23,8 +23,8 @@ It must print `v22` or higher.

## 1. A CAP project and the plugin

Skip `cds init` if you already have a CAP project and run the `npm install cap2ui5`
line in it.
Skip `cds init` if you already have a CAP project and run the
`npm add @cap2ui5/cds-plugin` line in it.

```bash
npm i -g @sap/cds-dk
Expand All @@ -40,16 +40,16 @@ not help. Then create the project and add the plugin:
cds init my-cap2ui5-app --nodejs --add tiny-sample
cd my-cap2ui5-app
npm install
npm install cap2ui5
npm add @cap2ui5/cds-plugin
```

`--add tiny-sample` gives the project something to read later: a service
`CatalogService` with one entity `Books` in `srv/cat-service.cds`, and five
books in `db/data/CatalogService.Books.csv`.

::: details Optional: check the CAP project before adding the plugin
Run `cds watch` after the first `npm install` and before `npm install cap2ui5`,
and open <http://localhost:4004>. CAP's index page lists the service endpoint
Run `cds watch` after the first `npm install` and before
`npm add @cap2ui5/cds-plugin`, and open <http://localhost:4004>. CAP's index page lists the service endpoint
`/odata/v4/catalog` with `Books`; the link answers the five books as JSON.
That is a plain CAP project working. Stop the server with `Ctrl+C` and go on.
:::
Expand All @@ -59,9 +59,9 @@ Two things about `cds init` that cost time when missed. Without `--nodejs`,
to install the plugin into. And it fails in a folder whose name contains a
space.

`npm install cap2ui5` is the whole installation. It brings two packages from
npm — `cap2ui5` and the `@abap2ui5/node-runtime` release it pins — and on the
next `cds watch` these exist that did not before:
`npm add @cap2ui5/cds-plugin` is the whole installation. It brings two
packages from npm — `@cap2ui5/cds-plugin` and the `@abap2ui5/node-runtime`
release it pins — and on the next `cds watch` these exist that did not before:

| | |
|---|---|
Expand All @@ -71,6 +71,20 @@ next `cds watch` these exist that did not before:
Your own `server.js`, if you have one, is not touched. Nothing is generated
into your repository, and there are no frontend files to serve.

::: info Coming from the package `cap2ui5`
Up to 0.2.0 the plugin was the unscoped package `cap2ui5`, which is withdrawn
from npm. A project that has it swaps it:

```bash
npm rm cap2ui5 && npm add @cap2ui5/cds-plugin
```

and its app modules import `@cap2ui5/cds-plugin` instead of `cap2ui5`.
Everything else keeps its name: the configuration `cds.requires.cap2ui5`,
`cds add cap2ui5`, `npx cap2ui5 abap2js`, the entity `cap2ui5.Drafts` and the
log `[cap2ui5]`.
:::

## 2. Your first app

One file in `srv/apps/` — the directory the plugin scans. It does not exist
Expand All @@ -85,7 +99,7 @@ yet in a new project:

```js
// srv/apps/hello.js
import { defineApp } from "cap2ui5";
import { defineApp } from "@cap2ui5/cds-plugin";

defineApp("HELLO", class {
name = "";
Expand Down Expand Up @@ -113,14 +127,14 @@ defineApp("HELLO", class {

::: warning `import`, not `require` — in this project
`cds init --nodejs` creates an **ES module** project (`"type": "module"` in
`package.json`), so a `.js` file there must `import`. A `require("cap2ui5")`
`package.json`), so a `.js` file there must `import`. A `require("@cap2ui5/cds-plugin")`
in it does not fail on its own line: it fails the **whole runtime boot** —
the log says `[cap2ui5] runtime failed to boot: ReferenceError: require is not
defined in ES module scope`, and every roundtrip, for every app, answers 500
"roundtrip failed".

In a CommonJS project (no `"type": "module"`), or in a file ending in `.cjs`,
`const { defineApp } = require("cap2ui5")` is correct and works the same way.
`const { defineApp } = require("@cap2ui5/cds-plugin")` is correct and works the same way.
The examples on this site use `import`, because that is what `cds init` gives
you.
:::
Expand Down Expand Up @@ -209,7 +223,7 @@ step 1 — save it as `srv/apps/books.js`, next to `hello.js`:
```js
// srv/apps/books.js
import cds from "@sap/cds";
import { defineApp, t } from "cap2ui5";
import { defineApp, t } from "@cap2ui5/cds-plugin";

const { SELECT } = cds.ql;

Expand Down Expand Up @@ -271,6 +285,24 @@ Open it: five books. Search for `Raven` and one row is left, with a toast
- **Column names are UPPERCASE in the view** — `{TITLE}`, not `{title}`. The
model carries field names uppercase; see [Data Binding](./data-binding#tables).

## The samples

abap2UI5's samples are a package too, `@cap2ui5/samples` — every sample a
cap2UI5 app, translated from its ABAP original line for line. Add it to the
project as a devDependency:

```bash
npm add -D @cap2ui5/samples
cds watch
```

The startup lines now list every sample beside `HELLO` and `BOOKS`, each under
its ABAP class name. As a devDependency the samples are there in development
only; a production start leaves them out. How a package brings apps is in
[Project Structure](./project-structure#apps-from-a-package), the list of
samples in the [cap2UI5/samples](https://github.com/cap2UI5/samples)
repository.

## What is in the database

`cds watch` runs on an **in-memory SQLite** and deploys every table at each
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ An app is a class. Each roundtrip rebuilds an instance of it from the draft,
applies what the browser sent, and calls `main(c)` exactly once.

```js
import { defineApp } from "cap2ui5";
import { defineApp } from "@cap2ui5/cds-plugin";

defineApp("ZCL_HELLO", class {
name = "";
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/migration-from-abap2ui5.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ ENDMETHOD.

```js
// cap2UI5
import { defineApp } from "cap2ui5";
import { defineApp } from "@cap2ui5/cds-plugin";

defineApp("ZCL_MY_APP", class {
name = "";
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/persistence.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ start:
```
[cds] - loaded model from 2 file(s):
srv/cat-service.cds
node_modules/cap2ui5/index.cds
node_modules/@cap2ui5/cds-plugin/index.cds
[cds] - connect to db > sqlite { url: ':memory:' }
```

Expand Down
Loading
Loading