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
31 changes: 23 additions & 8 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,19 @@ jobs:
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. Hence `check:ci` below, which passes
# --require-checkout: if this step is ever removed, renamed or fails to
# land the tree, the job goes red instead of quietly checking nothing.
# The documented targets. verify-refs checks every path, class, app id,
# plugin option and `require("cap2ui5")` 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
# passes --require-checkout: if a step is ever removed, renamed or fails
# to land the tree, the job goes red instead of quietly checking nothing.
#
# TWO checkouts since cap2UI5 became a plugin: cap2UI5 answers for repo
# paths, app ids, the plugin's exports and the pinned runtime release,
# while the FRAMEWORK CLASSES the docs name live in abap2UI5's ABAP —
# the runtime package is transpiled from it and is assembled rather than
# committed, so a fresh cap2UI5 checkout has none of those names.
- name: Check out cap2UI5 (reference target)
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand All @@ -44,6 +50,14 @@ jobs:
path: .cap2ui5-ref
fetch-depth: 1

- name: Check out abap2UI5 (the framework the runtime is built from)
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: abap2UI5/abap2UI5
ref: main
path: .abap2ui5-ref
fetch-depth: 1

- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '22'
Expand All @@ -53,8 +67,9 @@ jobs:
# verify-refs + vitepress build, in that order: a dead reference is
# reported even when the site would have built fine around it. Same two
# steps as the `npm run check` AGENTS.md tells a contributor to run —
# the :ci variant only refuses to skip the reference check.
# the :ci variant only refuses to skip the reference checks.
- name: npm run check:ci
run: npm run check:ci
env:
CAP2UI5_DIR: .cap2ui5-ref
ABAP2UI5_DIR: .abap2ui5-ref
118 changes: 64 additions & 54 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,74 +12,84 @@ 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 path named in the prose exists in a cap2UI5 checkout,
- 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")` **inside a code fence** destructures names the
package really exports (and the port's `require("abap2UI5/…")` is reported),
- 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.

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. That leniency is right on a laptop and wrong
in CI, which does check cap2UI5 out — so CI runs `npm run check:ci`, the same
two steps with `verify-refs --require-checkout`, and a missing checkout is a
failure there rather than a silent pass.
The verifier needs **two** checkouts: `CAP2UI5_DIR=/path/to/cap2UI5` and
`ABAP2UI5_DIR=/path/to/abap2UI5`, or sibling clones. It skips the checks a
missing checkout would need, so a green run without them proves only that the
site builds. That leniency is right on a laptop and wrong in CI, which checks
both out — so CI runs `npm run check:ci`, the same two steps with
`verify-refs --require-checkout`, and a missing checkout is a failure there
rather than a silent pass.

## Generated pages

`docs/guide/samples.md` is **generated** — do not edit it by hand. It comes
from `scripts/gen-samples.mjs`, which reads the sample gallery's own catalogue
table out of `z2ui5_cl_smp_app_000` in a cap2UI5 checkout:

```
CAP2UI5_DIR=/path/to/cap2UI5 npm run gen:samples # rewrite the page
node scripts/gen-samples.mjs --check # fail if it is out of date
```

The result is committed like any other page, so the docs build without a
checkout and a reviewer sees the diff a sync causes. Regenerate it when the
sample set changes.
Why two: cap2UI5 is a plugin, and the framework classes the docs name are not
in it. They are abap2UI5's ABAP, transpiled into `@abap2ui5/runtime`, whose
content is assembled by `scripts/assemble-runtime.sh` and gitignored — a fresh
cap2UI5 checkout has none of those names. Resolving classes against an
assembled runtime would pass on a laptop and check nothing in CI.

Exceptions — placeholder class names, paths in other repos — go in
`docs/.verify-refs-ignore`, **with a reason**. An unexplained entry there is
indistinguishable from suppressing a real defect.

## Ground truth — the cap2UI5 repo layout (since the monorepo split, 2026-07)
## Generated pages

None. `docs/guide/samples.md` and `scripts/gen-samples.mjs` were deleted with
the plugin cutover: the sample catalogue they mirrored belongs to abap2UI5's
sample repository, not to this site.

## Ground truth — the cap2UI5 repo layout (since the plugin cutover, 2026-09)

When documenting paths or linking sources, these are the facts (verify
against the repos, don't guess):

| Repo | Role |
|---|---|
| [cap2UI5/cap2UI5](https://github.com/cap2UI5/cap2UI5) | the deployable CAP app at the repo root — **generated** by builder-cap2UI5; framework vendored at `core/` (npm package `abap2UI5`, dep `"file:./core"`) |
| [cap2UI5/builder-abap2UI5-js](https://github.com/cap2UI5/builder-abap2UI5-js) | ABAP→JS transpiler + sync pipelines (update_samples/update_backend/update_frontend); generates the core package |
| [cap2UI5/builder-cap2UI5](https://github.com/cap2UI5/builder-cap2UI5) | assembles the app from its `src/` + the mirrored core; `update_cap` publishes into the app repo |
| [cap2UI5/builder-cap2UI5-web](https://github.com/cap2UI5/builder-cap2UI5-web) | browser-build tooling (formerly `web-cap2UI5`) |
| [cap2UI5/web-cap2UI5-build](https://github.com/cap2UI5/web-cap2UI5-build) | the built static site; GitHub Pages: https://cap2ui5.github.io/web-cap2UI5-build/ |

Path conventions inside the app repo:

- 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)`)
- webapp: `app/z2ui5/webapp/`; service: `srv/z2ui5-service.cds/.js`;
server wiring: `srv/server.js`; draft table: `db/schema.cds`
(`cap2ui5.z2ui5_t_01`)
| [cap2UI5/cap2UI5](https://github.com/cap2UI5/cap2UI5) | the npm package `cap2ui5`: a CAP plugin that hosts upstream's transpiled runtime |
| [abap2UI5/abap2UI5](https://github.com/abap2UI5/abap2UI5) | the framework itself, in ABAP. Downported and transpiled, it is published as `@abap2ui5/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.
There is no generated app, no vendored `core/`, no mirrored `app/z2ui5/webapp`.

Path conventions inside cap2UI5:

- `plugin/` — the package: `cds-plugin.js` (the route, the static shell, the
auth guard), `index.cds` (the `cap2ui5.Drafts` entity), `index.js` (what
`require("cap2ui5")` returns) and `lib/` (`define-app.js`, `define-exit.js`,
`draft-store.js`, `runtime.js`)
- `examples/bookshop/` — a CAP project using it, with the test suite. Its apps
are in `examples/bookshop/srv/apps/`
- `runtime/` — `@abap2ui5/runtime`. Only `package.json` and `README.md` are
committed; `output/`, `setup/` and `webapp/` are **assembled** and gitignored
- `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, the UI5 shell and
the draft entity from the plugin. `srv/`, `db/` and `app/` in the prose are
therefore **their** paths, which is why verify-refs does not check them
against the cap2UI5 repository.

## Rules

- Recommend `srv/app/` (never the samples folder) as the place for user
apps — pipeline-owned folders are overwritten on every sync/publish.
- Deep links must use the new repo roots (no `cap2UI5/cap2UI5/…/cap2UI5/…`
monorepo-subfolder links); verify every linked path exists.
- Run `npx vitepress build docs` before committing — it catches dead links.
- Recommend `srv/apps/` as the place for apps — it is the plugin's default.
- The framework's own classes are **not importable**. An app requires
`cap2ui5` and nothing else; `c.raw` is the escape hatch to the transpiled
`z2ui5_if_client`.
- 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
be given a host-side registration (`defineExit`) instead. Boot the runtime
and check rather than porting a claim from abap2UI5's documentation.
- Run `npm run check` before committing — verify-refs catches stale
references, the VitePress build catches dead links.
22 changes: 11 additions & 11 deletions docs/.verify-refs-ignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# Format: <token> # <reason>

# --- paths in OTHER repositories -------------------------------------------
app/webapp # the upstream abap2UI5 repo's frontend folder, which cap2UI5 mirrors
app/webapp # the upstream abap2UI5 repo's frontend folder, which @abap2ui5/runtime ships

# --- illustrative paths the READER creates ---------------------------------
srv/app/View1.view.xml # a static view file the getting-started example tells you to add
Expand All @@ -19,19 +19,19 @@ z2ui5_cl_app_xyz # stands for "your app class" in the interface descripti
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
zcl_my_app # stands for "the name you gave defineApp" in the why-cap2UI5 pitch
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
# Upstream's frozen src/99 needs no entries any more: the plugin hosts
# upstream's whole transpiled runtime, so z2ui5_cl_xml_view and its siblings
# ARE in it (measured in the assembled output) and resolve like any other
# class. They are still not what to write new code against — see
# guide/vs-abap2ui5 — but "do not use this" is a recommendation, and this file
# is only about what exists.

# --- release numbers that are NOT the pinned framework release --------------
# The pin itself (1.142.0 today) is read from the checkout and never listed
# --- release numbers that are NOT the pinned runtime release ----------------
# The pin itself (1.144.0 today) is read from the checkout and never listed
# here — listing it would keep the old number green after a pin move, which
# is the one defect the release check exists to catch.
1.143.0 # the upstream release where _bind/_bind_edit merged — history, stays true whatever the pin says
1.113.0 # the OpenUI5 release served locally — a UI5 number, not a framework release
1.113.0 # an OpenUI5 release — a UI5 number, not a framework release
11 changes: 3 additions & 8 deletions docs/.vitepress/config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,10 @@ export default defineConfig({
{ text: 'Examples', link: '/examples/hello-world' },
{ text: 'API', link: '/api/client' },
{ text: 'Reference', link: '/reference/architecture' },
{ text: 'Playground', link: 'https://cap2ui5.github.io/web-cap2UI5-build/' },
{
text: 'Links',
items: [
{ text: 'GitHub (cap2UI5)', link: 'https://github.com/cap2UI5/cap2UI5' },
{ text: 'GitHub (builder-cap2UI5-web)', link: 'https://github.com/cap2UI5/builder-cap2UI5-web' },
{ text: 'GitHub (docs)', link: 'https://github.com/cap2UI5/docs' },
{ text: 'abap2UI5', link: 'https://github.com/abap2UI5/abap2UI5' }
]
Expand All @@ -81,17 +79,15 @@ export default defineConfig({
items: [
{ text: 'What is cap2UI5?', link: '/guide/what-is-cap2ui5' },
{ text: 'Why cap2UI5?', link: '/guide/why-cap2ui5' },
{ text: 'Try It in the Browser', link: '/guide/playground' },
{ text: 'Quickstart', link: '/guide/getting-started' },
{ text: 'Project Structure', link: '/guide/project-structure' },
{ text: 'Sample Catalogue', link: '/guide/samples' }
{ text: 'Project Structure', link: '/guide/project-structure' }
]
},
{
text: 'Concepts',
items: [
{ text: 'App Lifecycle', link: '/guide/lifecycle' },
{ text: 'View Builder', link: '/guide/views' },
{ text: 'Views', link: '/guide/views' },
{ text: 'Data Binding', link: '/guide/data-binding' },
{ text: 'Events', link: '/guide/events' },
{ text: 'Navigation', link: '/guide/navigation' },
Expand Down Expand Up @@ -142,8 +138,7 @@ export default defineConfig({
{
text: 'API Reference',
items: [
{ text: 'client', link: '/api/client' },
{ text: 'View Builder', link: '/api/view-builder' },
{ text: 'c — the client facade', link: '/api/client' },
{ text: 'App Interface', link: '/api/app-interface' }
]
}
Expand Down
Loading
Loading