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 run/input/UPSTREAM_COMMIT
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7d1d58fb03e25330c632466412fd3824a7ee9ca8
ebbf20a37a55025c3ab2a48dee05dbdc0b461ac9
56 changes: 56 additions & 0 deletions run/input/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,62 @@ platform code**. Every platform consumes this one package:
> hand-edit it; edit `src/` and re-run `npm run build_core` at the
> [repo root](../).

## Using it in a CAP project

Two `using` lines and an install. The plugin does the rest — identity, the
draft store, app discovery, the bootstrap routes, the UI5 runtime mount and
the service implementation — because none of that is project-specific and
every consumer would otherwise copy the same ~160 lines and keep them in sync
by hand.

```jsonc
// package.json
{ "dependencies": { "abap2UI5": "..." } }
```

```cds
// db/schema.cds
using from 'abap2UI5/z2ui5-model'; // the draft table

// srv/service.cds
using from 'abap2UI5/z2ui5-service'; // the roundtrip endpoint
```

```js
// srv/app/my_app.js — your application
const z2ui5_if_app = require("abap2UI5/z2ui5_if_app");

class my_app extends z2ui5_if_app {
name = "";
main(client) {
if (client.get_event() === "SEND") client.message_toast_display(`Hi ${this.name}`);
client.view_display(/* ...view builder chain... */);
}
}
module.exports = my_app;
```

Point the framework at your apps with `Z2UI5_APP_DIRS` (path-separated) or
`require("abap2UI5/register-apps")(__dirname)`, then `cds watch` and open
`/rest/root/z2ui5`.

The plugin is opt-outable, whole or piecewise, for a project that wants to
wire something itself:

```jsonc
// package.json
{ "cds": { "z2ui5": { "routes": false } } } // or "activate": false
```

`abap2UI5/cap` exports the same `activate(options)` if you prefer to call it
explicitly — which is what the generated cap2UI5 app does, so the app's own
test suite exercises exactly the path an external consumer gets.

**TypeScript**: `types/index.d.ts` covers the app interface, the client, the
view-builder chain, the engine seam and the CAP entry point. The view builder
is the one that pays for itself — a fluent chain with no completion is a
guessing game.

## The seam

The platform surface is tiny — see [`srv/z2ui5/engine.js`](srv/z2ui5/engine.js):
Expand Down
40 changes: 40 additions & 0 deletions run/input/core/cds-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* cds-plugin — CAP loads this automatically for any project that depends on
* this package, which is the whole point: `npm i` and a z2ui5 project works,
* with no boilerplate to copy and keep in sync.
*
* What it wires is in srv/cap/activate.js; this file only decides whether to.
*
* Opting out, for a project that wants to wire things itself:
*
* // package.json
* "cds": { "z2ui5": { "activate": false } }
*
* or per concern — `{ "z2ui5": { "routes": false } }` — since a consumer that
* wants one piece done differently should not have to give up the rest. The
* same keys are accepted by activate() directly.
*
* Failure here is deliberately non-fatal. A plugin that throws takes the whole
* CAP server down with it, and this one is loaded into every dependent project
* — including ones that installed the package for its view builder and never
* intended to serve a z2ui5 endpoint at all.
*/
"use strict";

try {
const { activate, requireCds } = require("./srv/cap/activate");
// Not a plain require("@sap/cds"): this package is usually a `file:`
// dependency, npm symlinks those, and Node resolves from the real path —
// i.e. outside the consumer's tree. See requireCds for the full story.
const cds = requireCds();
const cfg = (cds && cds.env && cds.env.z2ui5) || {};

if (cds && cfg.activate !== false) {
const result = activate({ cds, ...cfg });
if (result.active && process.env.Z2UI5_LOG_PLUGIN !== "0") {
console.log(`[z2ui5] cds-plugin active on ${result.endpoint} (${result.applied.join(", ")})`);
}
}
} catch (e) {
console.error("[z2ui5] cds-plugin failed to activate:", e.message);
}
15 changes: 11 additions & 4 deletions run/input/core/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "abap2UI5",
"version": "1.0.0",
"description": "abap2UI5 core \u2014 the platform-neutral framework package: engine, transpiled classes, webapp and samples. Fully auto-generated (AI + sync pipeline).",
"description": "abap2UI5 core the platform-neutral framework package: engine, transpiled classes, webapp and samples. Fully auto-generated (AI + sync pipeline).",
"repository": "github:cap2UI5/cap2UI5",
"license": "MIT",
"private": true,
Expand All @@ -11,6 +11,13 @@
"exports": {
".": "./srv/z2ui5/00/03/z2ui5_cl_util.js",
"./engine": "./srv/z2ui5/engine.js",
"./cds-plugin": "./cds-plugin.js",
"./cap": "./srv/cap/activate.js",
"./cap-retention": "./srv/cap/retention.js",
"./z2ui5-model": "./z2ui5-model.cds",
"./z2ui5-model.cds": "./z2ui5-model.cds",
"./z2ui5-service": "./z2ui5-service.cds",
"./z2ui5-service.cds": "./z2ui5-service.cds",
"./z2ui5_asset": "./srv/z2ui5/z2ui5_asset.js",
"./z2ui5_identity": "./srv/z2ui5/z2ui5_identity.js",
"./z2ui5_preferred_param": "./srv/z2ui5/z2ui5_preferred_param.js",
Expand All @@ -19,6 +26,7 @@
"./cx_root": "./srv/z2ui5/00/00/cx_root.js",
"./z2ui5_cl_ui5_util_*": "./srv/z2ui5/00/03/z2ui5_cl_ui5_util_*.js",
"./z2ui5_cx_ui5_util_error": "./srv/z2ui5/00/03/z2ui5_cx_ui5_util_error.js",
"./z2ui5_html": "./srv/z2ui5/00/03/z2ui5_html.js",
"./z2ui5_cl_ui5_srv_draft": "./srv/z2ui5/01/01/z2ui5_cl_ui5_srv_draft.js",
"./z2ui5_cl_ui5_app_cont": "./srv/z2ui5/01/02/z2ui5_cl_ui5_app_cont.js",
"./z2ui5_cl_ui5_app_*": "./srv/z2ui5/01/04/z2ui5_cl_ui5_app_*.js",
Expand All @@ -37,8 +45,6 @@
"./z2ui5_cl_ajson": "./srv/z2ui5/00/01/z2ui5_cl_ajson.js",
"./z2ui5_cl_ajson_*": "./srv/z2ui5/00/01/z2ui5_cl_ajson_*.js",
"./z2ui5_cx_ajson_error": "./srv/z2ui5/00/01/z2ui5_cx_ajson_error.js",
"./z2ui5_cl_srt_*": "./srv/z2ui5/00/02/z2ui5_cl_srt_*.js",
"./z2ui5_cx_srt": "./srv/z2ui5/00/02/z2ui5_cx_srt.js",
"./z2ui5_cl_util": "./srv/z2ui5/00/03/z2ui5_cl_util.js",
"./z2ui5_cl_util_api": "./srv/z2ui5/00/03/02/z2ui5_cl_util_api.js",
"./z2ui5_cl_util_api_*": "./srv/z2ui5/00/03/02/z2ui5_cl_util_api_*.js",
Expand All @@ -49,5 +55,6 @@
},
"dependencies": {
"openui5-dist": "1.113.0"
}
},
"types": "./types/index.d.ts"
}
2 changes: 1 addition & 1 deletion run/input/core/srv/app/samples/z2ui5_cl_smp_app_000.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ class z2ui5_cl_smp_app_000 extends z2ui5_if_app {

block_base({ group, header } = {}) {
let result = ``;
if (String(group).includes(String(`controls -*`).replace(/\*/g, ""))) {
if ((($v, $p) => { let $r = ""; const $s = String($p); for (let $i = 0; $i < $s.length; $i++) { const $c = $s[$i]; if ($c === "#") { $i++; $r += ($s[$i] || "").replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } else if ($c === "*") { $r += ".*"; } else if ($c === "+") { $r += "."; } else { $r += $c.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } } return new RegExp("^" + $r + "$", "i").test(String($v)); })(group, `controls -*`)) {
result = header.substr(0, 1).toUpperCase();
} else {
result = this.header_base({ header: header });
Expand Down
2 changes: 1 addition & 1 deletion run/input/core/srv/app/samples/z2ui5_cl_smp_app_197.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class z2ui5_cl_smp_app_197 extends z2ui5_if_app {
}
this.mt_table = z2ui5_cl_util.abap_tab_assign(this.mt_table, z2ui5_cl_util.abap_copy(this.mt_table_full));
if (!z2ui5_cl_util.abap_is_initial(t_range)) {
for (let _i = this.mt_table.length - 1; _i >= 0; _i--) { const row = this.mt_table[_i]; if (!((($v, $r) => !$r || !$r.length || $r.some(($x) => ($x.option === `BT` ? $v >= $x.low && $v <= $x.high : $x.option === `NE` ? $v !== $x.low : $x.option === `CP` ? String($v).includes(String($x.low).replace(/\*/g, "")) : $v === $x.low)))(row.product, t_range))) this.mt_table.splice(_i, 1); }
for (let _i = this.mt_table.length - 1; _i >= 0; _i--) { const row = this.mt_table[_i]; if (!((($v, $r) => { if (!$r || !$r.length) return true; let $inc = false, $anyI = false, $exc = false; for (const $x of $r) { const $o = String($x.option || "EQ").toUpperCase(); const $hit = $o === "BT" ? $v >= $x.low && $v <= $x.high : $o === "NB" ? !($v >= $x.low && $v <= $x.high) : $o === "NE" ? $v !== $x.low : $o === "GT" ? $v > $x.low : $o === "GE" ? $v >= $x.low : $o === "LT" ? $v < $x.low : $o === "LE" ? $v <= $x.low : $o === "CP" ? (($v, $p) => { let $r = ""; const $s = String($p); for (let $i = 0; $i < $s.length; $i++) { const $c = $s[$i]; if ($c === "#") { $i++; $r += ($s[$i] || "").replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } else if ($c === "*") { $r += ".*"; } else if ($c === "+") { $r += "."; } else { $r += $c.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } } return new RegExp("^" + $r + "$", "i").test(String($v)); })($v, $x.low) : $o === "NP" ? !(($v, $p) => { let $r = ""; const $s = String($p); for (let $i = 0; $i < $s.length; $i++) { const $c = $s[$i]; if ($c === "#") { $i++; $r += ($s[$i] || "").replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } else if ($c === "*") { $r += ".*"; } else if ($c === "+") { $r += "."; } else { $r += $c.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } } return new RegExp("^" + $r + "$", "i").test(String($v)); })($v, $x.low) : $v === $x.low; if (String($x.sign || "I").toUpperCase() === "E") { if ($hit) $exc = true; } else { $anyI = true; if ($hit) $inc = true; } } return $exc ? false : ($anyI ? $inc : true); })(row.product, t_range))) this.mt_table.splice(_i, 1); }
}
}

Expand Down
Loading