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: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
node_modules/
# no lockfile, as in cap2UI5: CI tests what an install gets today (.github/workflows/test.yml)
package-lock.json
*.sqlite
*.sqlite-*
*.log
Expand Down
2 changes: 1 addition & 1 deletion ABAP2UI5_SAMPLES_PIN
Original file line number Diff line number Diff line change
@@ -1 +1 @@
cdd5c8b09a4ecdc51943b827ff6711d6c3af13a5
2e998ef1c90a1350e4ce1677bba59122fc8dac96
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,27 @@ versions [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

- The pin moves to abap2UI5/samples `2e998ef` (2026-09-30). `Z2UI5_CL_SMP_APP_173`
is translated again from its reworked original - a metadata-driven table
and form with `template:with`, nested `template:repeat` and
`template:if/elseif/else`. `Z2UI5_CL_SMP_APP_176` gained a button that
re-renders only the nested view, through an `ASSIGN mt_layout[ … ] TO
FIELD-SYMBOL( )` abap2js refuses, so it is ported by hand from here on and
listed under `handwritten`.
- Five of the nine samples abap2UI5/samples added since, translated by
abap2js: `Z2UI5_CL_SMP_APP_535` (CustomData writeToDom),
`Z2UI5_CL_SMP_APP_536` (custom data on controls), `Z2UI5_CL_SMP_APP_537`
(expressions, formatters and literals in `t_arg`), and two helper apps -
`Z2UI5_CL_SMP_APP_533`, the wizard with page transitions
`Z2UI5_CL_SMP_APP_531` calls, and `Z2UI5_CL_SMP_APP_534`, the popup-as-app
`Z2UI5_CL_SMP_APP_532` calls. 76 of abap2UI5's 138 samples. The other four
wait for abap2js: 531 reads a constant of another class, 532 uses `NEW`
outside the navigation, 538 `VALUE #( OPTIONAL … )`, 539 `SPLIT`.
- `npm run generate` (and its `--check`, the CI gate) refuses a module in
`srv/apps/` that `scripts/samples.json` does not list - such a module is
packed, served and started by the tests, but never held to its original by
the differential test, which reads `samples.json` - and names a listed
sample the checkout at the pin does not have instead of failing on the read.
- The differential test transpiles the originals against open-abap-core at the
commit `@abap2ui5/node-runtime` records in its `package.json`
(`abap2ui5.openAbapCore`) instead of HEAD, so the original runs on the
Expand Down
24 changes: 15 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ original's comments and texts, all of them, as they are.
`client->check_app_prev_stack( )` is `client.check_app_prev_stack()`.

> [!NOTE]
> **Status: 71 of the 129 samples.** 69 are generated by abap2js from
> **Status: 76 of the 138 samples.** 73 are generated by abap2js from
> abap2UI5/samples at the commit in [`ABAP2UI5_SAMPLES_PIN`](ABAP2UI5_SAMPLES_PIN),
> two are ported by hand; the [differential test](#the-differential-test) holds
> three are ported by hand; the [differential test](#the-differential-test) holds
> every one of them to its ABAP original.

## Add them to your project
Expand Down Expand Up @@ -76,6 +76,7 @@ open e.g. <http://localhost:4004/sap/bc/z2ui5?app_start=Z2UI5_CL_SMP_APP_493>.
| CSS - Color Table Cells from the Backend | [`Z2UI5_CL_SMP_APP_305`](srv/apps/z2ui5_cl_smp_app_305.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_305.clas.abap) |
| CSS - FlexBox Layouts with Custom Classes | [`Z2UI5_CL_SMP_APP_255`](srv/apps/z2ui5_cl_smp_app_255.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_255.clas.abap) |
| CSS - Ship Your Own CSS with the View | [`Z2UI5_CL_SMP_APP_050`](srv/apps/z2ui5_cl_smp_app_050.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_050.clas.abap) |
| CSS - Style by Data with CustomData writeToDom | [`Z2UI5_CL_SMP_APP_535`](srv/apps/z2ui5_cl_smp_app_535.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_535.clas.abap) |
| Control Behaviour - Aggregation Item by Index | [`Z2UI5_CL_SMP_APP_514`](srv/apps/z2ui5_cl_smp_app_514.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_514.clas.abap) |
| Control Behaviour - Expand a Panel by ID (setExpanded) | [`Z2UI5_CL_SMP_APP_448`](srv/apps/z2ui5_cl_smp_app_448.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_448.clas.abap) |
| Control Behaviour - Inline CSS on a Control (css) | [`Z2UI5_CL_SMP_APP_513`](srv/apps/z2ui5_cl_smp_app_513.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_513.clas.abap) |
Expand All @@ -87,6 +88,8 @@ open e.g. <http://localhost:4004/sap/bc/z2ui5?app_start=Z2UI5_CL_SMP_APP_493>.
| Device - Device Model: Phone, Tablet, Desktop | [`Z2UI5_CL_SMP_APP_445`](srv/apps/z2ui5_cl_smp_app_445.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_445.clas.abap) |
| Device - Frontend Info: UI5 Version, Theme, OS, Browser | [`Z2UI5_CL_SMP_APP_122`](srv/apps/z2ui5_cl_smp_app_122.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_122.clas.abap) |
| Device - Geolocation from the Browser | [`Z2UI5_CL_SMP_APP_120`](srv/apps/z2ui5_cl_smp_app_120.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_120.clas.abap) |
| Event - Custom Data Attached to Controls | [`Z2UI5_CL_SMP_APP_536`](srv/apps/z2ui5_cl_smp_app_536.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_536.clas.abap) |
| Event - Expressions, Formatters and Literals in t_arg | [`Z2UI5_CL_SMP_APP_537`](srv/apps/z2ui5_cl_smp_app_537.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_537.clas.abap) |
| Event - Extra Arguments with t_arg | [`Z2UI5_CL_SMP_APP_167`](srv/apps/z2ui5_cl_smp_app_167.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_167.clas.abap) |
| Event - Keep the Last Keystroke with check_queue_last | [`Z2UI5_CL_SMP_APP_511`](srv/apps/z2ui5_cl_smp_app_511.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_511.clas.abap) |
| Event - Link with preventDefault | [`Z2UI5_CL_SMP_APP_472`](srv/apps/z2ui5_cl_smp_app_472.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_472.clas.abap) |
Expand All @@ -110,6 +113,7 @@ open e.g. <http://localhost:4004/sap/bc/z2ui5?app_start=Z2UI5_CL_SMP_APP_493>.
| Navigation - Data Loss Protection on Leaving | [`Z2UI5_CL_SMP_APP_279`](srv/apps/z2ui5_cl_smp_app_279.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_279.clas.abap) |
| Navigation - Detail Page | [`Z2UI5_CL_SMP_APP_469`](srv/apps/z2ui5_cl_smp_app_469.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_469.clas.abap) |
| Navigation - Return Data and Events to the Caller | [`Z2UI5_CL_SMP_APP_488`](srv/apps/z2ui5_cl_smp_app_488.js) - by hand | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_488.clas.abap) |
| Navigation - Wizard Steps with Page Transitions (the app Z2UI5_CL_SMP_APP_531 calls) | [`Z2UI5_CL_SMP_APP_533`](srv/apps/z2ui5_cl_smp_app_533.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_533.clas.abap) |
| Nested View - Basic Example (nest_view_display) | [`Z2UI5_CL_SMP_APP_065`](srv/apps/z2ui5_cl_smp_app_065.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_065.clas.abap) |
| Nested View - Destroy and Target a Slot | [`Z2UI5_CL_SMP_APP_510`](srv/apps/z2ui5_cl_smp_app_510.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_510.clas.abap) |
| Popover - Basic Example with Placement | [`Z2UI5_CL_SMP_APP_026`](srv/apps/z2ui5_cl_smp_app_026.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_026.clas.abap) |
Expand All @@ -119,9 +123,10 @@ open e.g. <http://localhost:4004/sap/bc/z2ui5?app_start=Z2UI5_CL_SMP_APP_493>.
| Popup - Dialog inside a Dialog | [`Z2UI5_CL_SMP_APP_161`](srv/apps/z2ui5_cl_smp_app_161.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_161.clas.abap) |
| Popup - Element Binding to the Selected Row | [`Z2UI5_CL_SMP_APP_470`](srv/apps/z2ui5_cl_smp_app_470.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_470.clas.abap) |
| Popup - Navigate between Dialogs (NavContainer) | [`Z2UI5_CL_SMP_APP_170`](srv/apps/z2ui5_cl_smp_app_170.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_170.clas.abap) |
| Popup - Popup-as-App: a Dialog and no View (the app Z2UI5_CL_SMP_APP_532 calls) | [`Z2UI5_CL_SMP_APP_534`](srv/apps/z2ui5_cl_smp_app_534.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_534.clas.abap) |
| Table - Editable Cells, Add and Delete Rows | [`Z2UI5_CL_SMP_APP_011`](srv/apps/z2ui5_cl_smp_app_011.js) - by hand | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_011.clas.abap) |
| Templating - Build Columns Dynamically (template:repeat) | [`Z2UI5_CL_SMP_APP_173`](srv/apps/z2ui5_cl_smp_app_173.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_173.clas.abap) |
| Templating - Dynamic Content in a Nested View | [`Z2UI5_CL_SMP_APP_176`](srv/apps/z2ui5_cl_smp_app_176.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_176.clas.abap) |
| Templating - Metadata-Driven Table and Form | [`Z2UI5_CL_SMP_APP_173`](srv/apps/z2ui5_cl_smp_app_173.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_173.clas.abap) |
| Templating - Dynamic Content in a Nested View | [`Z2UI5_CL_SMP_APP_176`](srv/apps/z2ui5_cl_smp_app_176.js) - by hand | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_176.clas.abap) |
| Tree - Inside a Dialog | [`Z2UI5_CL_SMP_APP_462`](srv/apps/z2ui5_cl_smp_app_462.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_462.clas.abap) |
| Tree - Nested ABAP Table in a sap.m.Tree | [`Z2UI5_CL_SMP_APP_460`](srv/apps/z2ui5_cl_smp_app_460.js) | [abap](https://github.com/abap2UI5/samples/blob/main/src/z2ui5_cl_smp_app_460.clas.abap) |

Expand All @@ -140,9 +145,10 @@ is made:
- **`handwritten`** - a class abap2js refuses, ported by hand the way abap2js
would write it, with the construct it refuses as the reason:
`Z2UI5_CL_SMP_APP_011` (`LOOP AT t_tab REFERENCE INTO` writes through the
row, and `DELETE t_tab WHERE`) and `Z2UI5_CL_SMP_APP_488`
(`ASSIGN … ->* TO FIELD-SYMBOL( )`). A sample moves to `generated` when
abap2js learns the construct.
row, and `DELETE t_tab WHERE`), `Z2UI5_CL_SMP_APP_176`
(`ASSIGN mt_layout[ … ] TO FIELD-SYMBOL( )` writes through the row) and
`Z2UI5_CL_SMP_APP_488` (`ASSIGN … ->* TO FIELD-SYMBOL( )`). A sample moves
to `generated` when abap2js learns the construct.

The checkout is `--samples <dir>`, else `$ABAP2UI5_SAMPLES`, else
`../abap2UI5-samples`, and it has to be at the pin - `@origin` in a module
Expand Down Expand Up @@ -171,8 +177,8 @@ against the ABAP the runtime ships - renames it `ZABAP_SMP_APP_nnn` and serves
it beside the translation in one cap2UI5 server. Both are started, every event
the original's first view wires is fired on a fresh start of each, and what
comes back is compared: the XML of every view slot, the model the original
sends, every other action and which app has the screen - today 71 samples in
239 roundtrips, without a difference. One is known and left on purpose:
sends, every other action and which app has the screen - today 76 samples in
260 roundtrips, without a difference. One is known and left on purpose:
`Z2UI5_CL_SMP_APP_122` prints a number with `CONV string( )`, which keeps ABAP's
trailing sign position (`"0 "`) and JavaScript's `String( )` does not.

Expand Down
15 changes: 15 additions & 0 deletions scripts/generate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,26 @@ if (overlap.length) {
console.error(`generate: ${overlap.join(", ")} listed as generated AND handwritten in scripts/samples.json`);
process.exit(1);
}
// A module in srv/apps that samples.json does not list is packed, served and
// started by the tests like any other - but never held to an original by the
// differential test, which reads samples.json. So it is listed, or it goes.
const orphans = fs.readdirSync(path.join(ROOT, "srv", "apps"))
.filter((f) => /^z2ui5_cl_smp_app_\d+\.js$/.test(f)).map((f) => f.replace(/\.js$/, ""))
.filter((n) => !generated.includes(n) && !(n in handwritten));
if (orphans.length) {
console.error(`generate: srv/apps/${orphans.join(".js, srv/apps/")}.js not listed in scripts/samples.json - list it, or delete it`);
process.exit(1);
}

let failed = 0;
let changed = 0;
for (const name of generated) {
const file = path.join(src, `${name}.clas.abap`);
if (!fs.existsSync(file)) {
console.error(`missing: src/${name}.clas.abap is not in abap2UI5/samples@${pin.slice(0, 7)} - is the name right?`);
failed++;
continue;
}
let code;
try {
({ code } = abap2js(fs.readFileSync(file, "utf8"), {
Expand Down
5 changes: 5 additions & 0 deletions scripts/originals.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ const pin = fs.readFileSync(path.join(ROOT, "ABAP2UI5_SAMPLES_PIN"), "utf8").tri
const { generated, handwritten } = JSON.parse(fs.readFileSync(path.join(ROOT, "scripts", "samples.json"), "utf8"));
const names = [...generated, ...Object.keys(handwritten)];

if (!fs.existsSync(path.join(checkout, "src"))) {
console.error(`originals: no abap2UI5/samples checkout at ${checkout} - clone it and check out ${pin}:\n` +
` git clone https://github.com/abap2UI5/samples ${checkout} && git -C ${checkout} checkout ${pin}`);
process.exit(1);
}
const head = execFileSync("git", ["-C", checkout, "rev-parse", "HEAD"], { encoding: "utf8" }).trim();
if (head !== pin) throw new Error(`${checkout} is at ${head}, ABAP2UI5_SAMPLES_PIN says ${pin}`);

Expand Down
9 changes: 7 additions & 2 deletions scripts/samples.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"z2ui5_cl_smp_app_167",
"z2ui5_cl_smp_app_170",
"z2ui5_cl_smp_app_173",
"z2ui5_cl_smp_app_176",
"z2ui5_cl_smp_app_186",
"z2ui5_cl_smp_app_189",
"z2ui5_cl_smp_app_202",
Expand Down Expand Up @@ -69,10 +68,16 @@
"z2ui5_cl_smp_app_515",
"z2ui5_cl_smp_app_516",
"z2ui5_cl_smp_app_518",
"z2ui5_cl_smp_app_519"
"z2ui5_cl_smp_app_519",
"z2ui5_cl_smp_app_533",
"z2ui5_cl_smp_app_534",
"z2ui5_cl_smp_app_535",
"z2ui5_cl_smp_app_536",
"z2ui5_cl_smp_app_537"
],
"handwritten": {
"z2ui5_cl_smp_app_011": "LOOP AT t_tab REFERENCE INTO writes through the row, and DELETE t_tab WHERE (abap2js: neither supported yet)",
"z2ui5_cl_smp_app_176": "ASSIGN mt_layout[ fname = ... ] TO FIELD-SYMBOL( ) writes through the row (abap2js: ASSIGN not supported yet)",
"z2ui5_cl_smp_app_488": "ASSIGN ls_get-r_event_data->* TO FIELD-SYMBOL( ) (abap2js: not supported yet)"
}
}
Loading
Loading