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
44 changes: 38 additions & 6 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,45 @@
# Why this file exists, and what it has to keep moving.
#
# Every workflow in this repository pins its actions to a commit SHA rather
# than to `@v7`. A tag is a pointer its owner can move, so a job pinned to one
# runs whatever it points at that day; a commit cannot change under you. The
# cost of that safety is that nothing bumps a pin on its own — a pinned action
# quietly becomes a stale action, which is exactly what happened here: the
# deploy workflow sat two majors behind the rest of the organisation until
# somebody read the two files side by side. This is the PR that says so.
#
# Two ecosystems, matching the rest of the organisation:
#
# npm vitepress. It builds the site, and the build is half of
# `npm run check` — the gate every pull request passes.
# github-actions the deploy and check workflows. Dependabot updates a SHA
# pin in place and keeps the version comment right, so pinned
# does not become stale.
version: 2
updates:
# The other repos in the ecosystem pin their actions to commit SHAs, which
# means nothing bumps them without a PR — this is that PR.
- package-ecosystem: github-actions
directory: /
- package-ecosystem: npm
directory: "/"
schedule:
interval: weekly
day: monday
time: "06:23"
timezone: Etc/UTC
open-pull-requests-limit: 5
groups:
# One PR for the toolchain rather than one per package: they move
# together, and what has to be verified is a site that still builds, not
# each package alone.
toolchain:
patterns: ["*"]

- package-ecosystem: npm
directory: /
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
day: monday
time: "06:23"
timezone: Etc/UTC
open-pull-requests-limit: 5
groups:
actions:
patterns: ["*"]
56 changes: 56 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# What a pull request against this documentation gets checked for.
#
# There was nothing before this. verify-refs existed, but it ran only inside
# deploy.yml — which runs on push to main, so the one gate that decides whether
# the prose is still true about the code first spoke AFTER the merge, on the
# published site. That is how thirteen pages could go on teaching a class the
# framework had removed: nothing failed, because nothing ran in time.
#
# The job runs `npm run check` — the same command AGENTS.md tells a contributor
# to run locally, so a green machine and a green CI mean the same thing.
name: check

on:
push:
branches: [main]
pull_request:

concurrency:
group: check-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

# The documented target. verify-refs checks every path, class, sample id
# and `require("abap2UI5/…")` on this site against a real checkout, so
# without it the run proves only that the site builds — it skips itself
# and exits 0 when the checkout is missing, which is exactly the silent
# pass this job exists to prevent.
- name: Check out cap2UI5 (reference target)
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: cap2UI5/cap2UI5
ref: main
path: .cap2ui5-ref
fetch-depth: 1

- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '22'
cache: 'npm'
- run: npm ci

# verify-refs + vitepress build, in that order: a dead reference is
# reported even when the site would have built fine around it.
- name: npm run check
run: npm run check
env:
CAP2UI5_DIR: .cap2ui5-ref
28 changes: 14 additions & 14 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,42 +19,42 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0

- name: Setup Node
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
cache: npm

- name: Setup Pages
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0

- name: Install dependencies
run: npm ci

# The docs make concrete claims about the cap2UI5 repository — paths,
# class names, sample ids. Nothing else checks them: `vitepress build`
# validates internal links and stops there, so every rename upstream
# silently rots the prose. Verify against the real app.
# class names, sample ids, imports. Nothing else checks them:
# `vitepress build` validates internal links and stops there, so every
# rename upstream silently rots the prose. Verify against the real app.
- name: Check out cap2UI5 (reference target)
uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: cap2UI5/cap2UI5
path: .cap2ui5-ref

- name: Verify documented references
run: node scripts/verify-refs.mjs
# verify-refs + vitepress build, through the same `npm run check` a
# contributor runs locally and check.yml runs on the pull request — one
# command, so the three cannot drift into checking different things.
- name: Check (verify-refs + build)
run: npm run check
env:
CAP2UI5_DIR: .cap2ui5-ref

- name: Build with VitePress
run: npm run docs:build

- name: Upload artifact
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: docs/.vitepress/dist

Expand All @@ -67,4 +67,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
32 changes: 23 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,19 @@ The VitePress documentation site for cap2UI5 (`docs/` holds the content,
`docs/.vitepress/config.mjs` the nav/sidebar). Build locally with
`npm ci && npx vitepress build docs`; dev server via `npx vitepress dev docs`.

Before committing, run `npm run check` — that is `verify-refs` (every path,
class and `?app_start=` named in the prose must resolve in a real cap2UI5
checkout, and every internal anchor must exist) followed by the VitePress
build. The verifier needs a checkout: `CAP2UI5_DIR=/path/to/cap2UI5`, or a
sibling clone. It skips itself when there is none, so a green run without a
checkout proves only that the site builds.
Before committing, run `npm run check` — that is `verify-refs` followed by the
VitePress build. It is also what CI runs, on every pull request
(`.github/workflows/check.yml`) and on deploy. verify-refs checks that

- every path, class and `?app_start=` named in the prose resolves in a real
cap2UI5 checkout,
- every `require("abap2UI5/…")` **inside a code fence** resolves through the
exports map of `core/package.json` and onto a file that exists,
- every internal anchor exists.

The verifier needs a checkout: `CAP2UI5_DIR=/path/to/cap2UI5`, or a sibling
clone. It skips itself when there is none, so a green run without a checkout
proves only that the site builds.

Exceptions — placeholder class names, paths in other repos — go in
`docs/.verify-refs-ignore`, **with a reason**. An unexplained entry there is
Expand All @@ -34,9 +41,16 @@ against the repos, don't guess):

Path conventions inside the app repo:

- framework classes: `core/srv/z2ui5/` (layers `00/` utils, `01/` core
plumbing — including the shipped apps in `01/04/` since the 2026-08
upstream rename, `02/` public API, `99/` add-ons like the pop helpers)
- framework classes: `core/srv/z2ui5/` — exactly three layers: `00/` utils,
`01/` core plumbing (including the shipped apps in `01/04/` since the
2026-08 upstream rename) and `02/` public API. There is no `99/`: upstream's
frozen legacy package is deliberately not carried into the port, so
`z2ui5_cl_xml_view`, `z2ui5_cl_xml_view_cc` and the `z2ui5_cl_pop_*` popups
do not exist here. The one view builder is `z2ui5_cl_ui5_view_builder`.
- the vendored release is pinned: `z2ui5_if_app.version` says which one
(1.142.0 today). On it `_bind` is one-way and `_bind_edit` two-way —
upstream merged the two in 1.143.0, so upstream material can disagree with
what this core does.
- bundled demo samples (pipeline-owned, flat): `core/srv/app/samples/`
- user apps: `srv/app/` (or any folder via `Z2UI5_APP_DIRS` /
`require("abap2UI5/register-apps")(dir)`)
Expand Down
35 changes: 19 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# cap2UI5 — Documentation

VitePress documentation for [**cap2UI5**](https://github.com/cap2UI5/cap2UI5) — the CAP / Node.js port of the [abap2UI5](https://github.com/abap2UI5/abap2UI5) concept. 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)).
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)).

## Develop locally

```bash
npm install
npm ci
npm run docs:dev
```

Expand All @@ -18,22 +20,23 @@ npm run docs:build # → docs/.vitepress/dist
npm run docs:preview # → preview server
```

## Structure
## Check before you commit

```bash
CAP2UI5_DIR=/path/to/cap2UI5 npm run check
```
.
├── docs/
│ ├── .vitepress/
│ │ ├── config.mjs # VitePress configuration
│ │ └── theme/ # Custom theme (red brand color)
│ ├── index.md # Landing page
│ ├── guide/ # Concepts, quickstart, lifecycle, bindings, …
│ ├── examples/ # End-to-end example apps
│ ├── api/ # API reference (client, View Builder, App Interface)
│ └── reference/ # Architecture, protocol, DB, deployment
├── package.json
└── README.md
```

`npm run check` is `verify-refs` followed by the VitePress build, and it is exactly what CI runs — on every pull request (`.github/workflows/check.yml`) and again on deploy. It is the only gate this repository has on whether the prose is still true about the code:

- every path, class and `?app_start=` named in the docs must exist in a real [cap2UI5](https://github.com/cap2UI5/cap2UI5) checkout,
- every `require("abap2UI5/…")` in a code example must resolve through the exports map of `core/package.json`,
- every internal anchor must exist.

`verify-refs` needs that checkout — pass `CAP2UI5_DIR`, or clone cap2UI5 next to this repository. **Without one it skips itself and exits 0**, so a green run with no checkout proves only that the site builds. Deliberate exceptions live in `docs/.verify-refs-ignore`, each with a reason.

## Structure

The folder scheme, the ground truth about the cap2UI5 repo layout and the rules for linking into it are in **[AGENTS.md](AGENTS.md)** — read it before making any change.

## License

Expand Down
9 changes: 9 additions & 0 deletions docs/.verify-refs-ignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,13 @@ 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 # same, in the why-cap2ui5 pitch
my_app_name # stands for "your class" in the ?app_start= URL on the navigation page
ClassName # literal placeholder in the URL-parameter description

# --- classes that exist UPSTREAM and deliberately not here -----------------
# cap2UI5 does not carry abap2UI5's frozen src/99 (see guide/vs-abap2ui5). The
# names are named there precisely to say they are absent, so the checker must
# not read the mention as a claim that they exist.
z2ui5_cl_xml_view # upstream's retired view builder — replaced here by z2ui5_cl_ui5_view_builder
z2ui5_cl_xml_view_cc # its custom-control decorator, retired with it
z2ui5_cl_pop_bal # one of upstream's frozen built-in popups, superseded by the popups add-on
33 changes: 29 additions & 4 deletions docs/.vitepress/config.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { defineConfig } from 'vitepress'

// Where the site is actually served from. Link previews (LinkedIn, Slack,
// WhatsApp, X) only accept ABSOLUTE urls in og:image — a relative
// "/docs/logo.jpeg" is silently dropped and the preview falls back to the
// grey placeholder card.
const SITE_URL = 'https://cap2ui5.github.io/docs'
const OG_IMAGE = `${SITE_URL}/logo.jpeg`

export default defineConfig({
title: 'cap2UI5',
description: 'Bringing the abap2UI5 concept to CAP / Node.js — server-driven UI5 apps written in pure JavaScript',
Expand All @@ -20,10 +27,24 @@ export default defineConfig({
},

head: [
['link', { rel: 'icon', type: 'image/jpeg', href: '/docs/logo.jpeg' }],
['link', { rel: 'apple-touch-icon', href: '/docs/logo.jpeg' }],
['meta', { name: 'theme-color', content: '#d03c4a' }],
['meta', { property: 'og:type', content: 'website' }],
['meta', { property: 'og:site_name', content: 'cap2UI5' }],
['meta', { property: 'og:url', content: `${SITE_URL}/` }],
['meta', { property: 'og:title', content: 'cap2UI5 — Server-driven UI5 for CAP' }],
['meta', { property: 'og:description', content: 'Build full UI5 applications from your CAP backend in JavaScript — no separate frontend project, no XML hand-crafting.' }]
['meta', { property: 'og:description', content: 'Build full UI5 applications from your CAP backend in JavaScript — no separate frontend project, no XML hand-crafting.' }],
['meta', { property: 'og:image', content: OG_IMAGE }],
['meta', { property: 'og:image:type', content: 'image/jpeg' }],
// The logo is square (790x790), so the preview is a thumbnail card, not a
// wide banner — declaring the real size is what keeps it from being
// cropped. A 1200x630 banner would earn the large card; there is none yet.
['meta', { property: 'og:image:width', content: '790' }],
['meta', { property: 'og:image:height', content: '790' }],
['meta', { property: 'og:image:alt', content: 'cap2UI5 — server-driven UI5 for CAP' }],
['meta', { name: 'twitter:card', content: 'summary' }],
['meta', { name: 'twitter:image', content: OG_IMAGE }]
],

themeConfig: {
Expand Down Expand Up @@ -52,9 +73,6 @@ export default defineConfig({
text: 'Getting Started',
items: [
{ text: 'What is cap2UI5?', link: '/guide/what-is-cap2ui5' },
{ text: 'Server-Driven UI, Explained', link: '/guide/server-driven-ui' },
{ text: 'Where cap2UI5 Comes From', link: '/guide/where-it-comes-from' },
{ text: 'The Ecosystem', link: '/guide/ecosystem' },
{ text: 'Why cap2UI5?', link: '/guide/why-cap2ui5' },
{ text: 'Try It in the Browser', link: '/guide/playground' },
{ text: 'Quickstart', link: '/guide/getting-started' },
Expand Down Expand Up @@ -86,6 +104,13 @@ export default defineConfig({
{ text: 'cap2UI5 vs. Fiori Elements', link: '/guide/vs-fiori-elements' },
{ text: 'cap2UI5 vs. abap2UI5', link: '/guide/vs-abap2ui5' }
]
},
{
text: 'Background',
items: [
{ text: 'Where cap2UI5 Comes From', link: '/guide/where-it-comes-from' },
{ text: 'The Ecosystem', link: '/guide/ecosystem' }
]
}
],

Expand Down
15 changes: 12 additions & 3 deletions docs/api/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,22 @@ The `client` object is the only interface your app has to the outside world duri

| Method | Returns | Description |
|---|---|---|
| `_bind(value, opts?)` | `string` | One-way binding → `{/path}` |
| `_bind_edit(value, opts?)` | `string` | Two-way binding → `{/XX/path}` |
| `_bind_local(value)` | `string` | Local binding without an app property |
| `_bind(value, opts?)` | `string` | One-way binding → `{/PATH}` |
| `_bind_edit(value, opts?)` | `string` | Two-way binding → `{/XX/PATH}` |
| `_bind_local(value)` | `string` | Local binding without an app property → `{/__local_N}` |

Paths are uppercased (`this.user_name` → `/XX/USER_NAME`) and mapped back onto the real property case-insensitively when the delta returns.

::: info The two are one method upstream — but not here
On the framework release cap2UI5 pins (**1.142.0**, `z2ui5_if_app.version`) these are genuinely two bindings: `_bind` writes into the model root and is read-only on the frontend, `_bind_edit` writes into the `XX` namespace the frontend can write back through. That is what `z2ui5_cl_ui5_srv_bind` does in the shipped code, and what this documentation describes throughout.

abap2UI5 resolved the split in **1.143.0**: there `_bind_edit` is an alias of `_bind`, and the reverse-formatter options are accepted but ignored. If you are reading upstream material, that is the difference you are looking at. → [cap2UI5 vs. abap2UI5](../guide/vs-abap2ui5)
:::

**`opts`** for `_bind` / `_bind_edit`:
- `path: true` → returns the bare path without `{...}`
- `path: "name"` → explicit path, no reference lookup
- `name: "s_screen-city"` → resolve a member inside a bound structure by name
- `custom_mapper: ".fmt"` → formatter function name
- `custom_mapper_back: ".fmtBack"` → reverse formatter (only `_bind_edit`)
- `custom_filter: ".f"` / `custom_filter_back: ".fb"` → aliases
Expand Down
Loading