cds-plugin-ui5 0.6.2 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,28 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.6.4](https://github.com/ui5-community/ui5-ecosystem-showcase/compare/cds-plugin-ui5@0.6.3...cds-plugin-ui5@0.6.4) (2023-09-10)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **cds-plugin-ui5:** rewrite UI5 server listing also in approuter ([#839](https://github.com/ui5-community/ui5-ecosystem-showcase/issues/839)) ([f501558](https://github.com/ui5-community/ui5-ecosystem-showcase/commit/f501558b47051606606c4b5289bc60d43018031f))
12
+
13
+
14
+
15
+
16
+
17
+ ## [0.6.3](https://github.com/ui5-community/ui5-ecosystem-showcase/compare/cds-plugin-ui5@0.6.2...cds-plugin-ui5@0.6.3) (2023-09-08)
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * **cds-plugin-ui5:** fix type for config ([ebd95f0](https://github.com/ui5-community/ui5-ecosystem-showcase/commit/ebd95f0e5a269c769587e7c9c3bdf6885fc7ca3d))
23
+
24
+
25
+
26
+
27
+
6
28
  ## [0.6.2](https://github.com/ui5-community/ui5-ecosystem-showcase/compare/cds-plugin-ui5@0.6.1...cds-plugin-ui5@0.6.2) (2023-09-08)
7
29
 
8
30
 
package/cds-plugin.js CHANGED
@@ -5,6 +5,7 @@ const log = require("./lib/log");
5
5
  const findUI5Modules = require("./lib/findUI5Modules");
6
6
  const createPatchedRouter = require("./lib/createPatchedRouter");
7
7
  const applyUI5Middleware = require("./lib/applyUI5Middleware");
8
+ const rewriteHTML = require("./lib/rewriteHTML");
8
9
 
9
10
  // marker that the cds-plugin-ui5 plugin is running
10
11
  // to disable the ui5-middleware-cap if used in apps
@@ -67,18 +68,20 @@ cds.on("bootstrap", async function bootstrap(app) {
67
68
  if (links.length > 0) {
68
69
  // register the custom middleware (similar like in @sap/cds/server.js)
69
70
  app.get("/", function appendLinksToIndex(req, res, next) {
70
- const send = res.send;
71
- res.send = function (content) {
72
- // the first <ul> element contains the links to the
73
- // application pages which is fully under control of
74
- // our plugin now and we keep all links to static
75
- // pages to ensure coop with classic apps
76
- const HTMLParser = require("node-html-parser");
77
- const doc = new HTMLParser.parse(content);
78
- const head = doc.getElementsByTagName("head")?.[0];
79
- if (head) {
80
- head.appendChild(
81
- HTMLParser.parse(`<style>
71
+ req._cds_plugin_ui5 = true; // marker for patched router to ignore
72
+ rewriteHTML(
73
+ req,
74
+ res,
75
+ () => true,
76
+ (doc) => {
77
+ // the first <ul> element contains the links to the
78
+ // application pages which is fully under control of
79
+ // our plugin now and we keep all links to static
80
+ // pages to ensure coop with classic apps
81
+ const head = doc.getElementsByTagName("head")?.[0];
82
+ head?.insertAdjacentHTML(
83
+ "beforeend",
84
+ `<style>
82
85
  a.ui5:after {
83
86
  content: "UI5";
84
87
  font-weight: bold;
@@ -92,27 +95,25 @@ cds.on("bootstrap", async function bootstrap(app) {
92
95
  color: #FF5A37;
93
96
  }
94
97
  }
95
- </style>`)
98
+ </style>`
96
99
  );
100
+ const ul = doc.getElementsByTagName("ul")?.[0];
101
+ if (ul) {
102
+ const newLis = [];
103
+ const lis = ul.getElementsByTagName("li");
104
+ lis?.forEach((li) => {
105
+ const appDir = li.firstChild?.text?.split("/")?.[1];
106
+ if (localApps.has(appDir)) {
107
+ newLis.push(li.toString());
108
+ }
109
+ });
110
+ newLis.push(...links.map((link) => `<li><a class="ui5" href="${link}">${link}</a></li>`));
111
+ ul.innerHTML = newLis.join("\n");
112
+ } else {
113
+ log.warn(`Failed to inject application links into CAP index page!`);
114
+ }
97
115
  }
98
- const ul = doc.getElementsByTagName("ul")?.[0];
99
- if (ul) {
100
- const newLis = [];
101
- const lis = ul.getElementsByTagName("li");
102
- lis?.forEach((li) => {
103
- const appDir = li.firstChild?.text?.split("/")?.[1];
104
- if (localApps.has(appDir)) {
105
- newLis.push(li.toString());
106
- }
107
- });
108
- newLis.push(...links.map((link) => `<li><a class="ui5" href="${link}">${link}</a></li>`));
109
- ul.innerHTML = newLis.join("\n");
110
- content = doc.toString();
111
- } else {
112
- log.warn(`Failed to inject application links into CAP index page!`);
113
- }
114
- send.apply(this, arguments);
115
- };
116
+ );
116
117
  next();
117
118
  });
118
119
 
@@ -41,7 +41,7 @@ module.exports = async function applyUI5Middleware(router, options) {
41
41
  const configPath = options.configPath || options.basePath;
42
42
  const configFile = options.configFile || "ui5.yaml";
43
43
  const workspaceConfigPath = options.workspaceConfigPath || options.basePath;
44
- const workpaceConfigFile = options.workpaceConfigFile || "ui5-workspace.yaml";
44
+ const workspaceConfigFile = options.workspaceConfigFile || "ui5-workspace.yaml";
45
45
 
46
46
  const determineConfigPath = function (configPath, configFile) {
47
47
  // ensure that the config path is absolute
@@ -69,7 +69,7 @@ module.exports = async function applyUI5Middleware(router, options) {
69
69
  cwd: options.basePath,
70
70
  rootConfigPath: determineConfigPath(configPath, configFile),
71
71
  workspaceName: process.env["ui5-workspace"] || options.workspaceName || "default",
72
- workspaceConfigPath: determineConfigPath(workspaceConfigPath, workpaceConfigFile),
72
+ workspaceConfigPath: determineConfigPath(workspaceConfigPath, workspaceConfigFile),
73
73
  versionOverride: options.versionOverride,
74
74
  cacheMode: options.cacheMode,
75
75
  });
@@ -1,4 +1,5 @@
1
1
  const { Router } = require("express");
2
+ const rewriteHTML = require("./rewriteHTML");
2
3
 
3
4
  /**
4
5
  * Creates a patched router removing the mount path
@@ -9,12 +10,6 @@ module.exports = async function createPatchedRouter() {
9
10
  // create the router and get rid of the mount path
10
11
  const router = new Router();
11
12
  router.use(function (req, res, next) {
12
- // disable the compression when livereload is used
13
- // for loading html-related content (via accept header)
14
- const accept = req.headers["accept"]?.indexOf("html") !== -1;
15
- if (accept && res._livereload) {
16
- req.headers["accept-encoding"] = "identity";
17
- }
18
13
  // store the original request information
19
14
  const { url, originalUrl, baseUrl } = req;
20
15
  req["cds-plugin-ui5"] = {
@@ -25,28 +20,46 @@ module.exports = async function createPatchedRouter() {
25
20
  // rewite the path to simulate requests on the root level
26
21
  req.originalUrl = req.url;
27
22
  req.baseUrl = "/";
28
- // try to override UI5 tooling directory listing
29
- if (req.url?.endsWith("/")) {
30
- const end = res.end;
31
- res.end = function (content) {
32
- const contentType = res.getHeader("content-type");
33
- if (content && contentType?.indexOf("text/html") !== -1) {
34
- const HTMLParser = require("node-html-parser");
35
- const doc = new HTMLParser.parse(content);
23
+ // override UI5 server directory listing if:
24
+ // 1.) not handled by the CDS Plugin UI5 already
25
+ // 2.) only if it ends with a slash
26
+ // 3.) not forwarded to a welcome page
27
+ if (!req._cds_plugin_ui5 && req.url?.endsWith("/") && req.url === (req?.["ui5-middleware-index"]?.url || req.url)) {
28
+ // determine context path (approuter contains x-forwarded-path header)
29
+ let contextPath = baseUrl;
30
+ if (req.headers["x-forwarded-path"]) {
31
+ // determine the context path by removing the subpath from the forwarded path
32
+ contextPath = req.headers["x-forwarded-path"].slice(0, -1 * url.length);
33
+ } else if (req["cds-plugin-ui5"].originalUrl) {
34
+ // determine the context path by removing the subpath from the originalUrl
35
+ contextPath = req["cds-plugin-ui5"].originalUrl.slice(0, -1 * url.length);
36
+ }
37
+ rewriteHTML(
38
+ req,
39
+ res,
40
+ (res) => {
41
+ const contentType = res.getHeader("content-type");
42
+ return contentType?.indexOf("text/html") !== -1;
43
+ },
44
+ (doc) => {
36
45
  const title = doc.getElementsByTagName("title")?.[0];
37
46
  if (title) {
38
- title.innerHTML = `Index of ${baseUrl}/`;
47
+ title.innerHTML = `Index of ${contextPath}/`;
39
48
  }
40
- const as = doc.getElementsByTagName("a");
41
- as?.forEach((a) => {
42
- a.setAttribute("href", `${baseUrl}${a.getAttribute("href")}`);
49
+ const files = doc.getElementById("files");
50
+ const filesas = files?.getElementsByTagName("a");
51
+ filesas?.forEach((a) => {
52
+ a.setAttribute("href", `${contextPath}${a.getAttribute("href")}`);
43
53
  });
44
54
  const h1 = doc.getElementsByTagName("h1")?.[0];
45
- h1?.insertAdjacentHTML("afterbegin", `<a href="/">@sap/cds</a> &gt; `);
46
- content = doc.toString();
55
+ const h1as = h1?.getElementsByTagName("a");
56
+ h1as?.forEach((a) => {
57
+ const path = a.getAttribute("href") === "/" ? "/" : a.getAttribute("href") + "/";
58
+ a.setAttribute("href", `${contextPath}${path}`);
59
+ });
60
+ h1?.insertAdjacentHTML("afterbegin", `<a href="/">🏡</a> / `);
47
61
  }
48
- end.apply(res, arguments);
49
- };
62
+ );
50
63
  }
51
64
  // next one!
52
65
  next();
@@ -0,0 +1,75 @@
1
+ const http = require("http");
2
+ const HTMLParser = require("node-html-parser");
3
+
4
+ /**
5
+ * Callback from the `rewriteHTML` function to determine whether the response should be rewritten
6
+ *
7
+ * @callback rewriteCondition
8
+ * @param {http.OutgoingMessage} req http request object
9
+ * @returns {boolean} true, if the response should be rewritten and the `rewriteContent` callback called
10
+ */
11
+
12
+ /**
13
+ * Callback from the `rewriteHTML` function to modify the HTML document
14
+ *
15
+ * @callback rewriteContent
16
+ * @param {HTMLParser.HTMLElement} doc the HTML document
17
+ * @returns {void}
18
+ */
19
+
20
+ /**
21
+ * Intercepts the response and calls back the given `rewriteContent` function
22
+ * which could then rewrite the HTML content via the DOM tree.
23
+ *
24
+ * @param {http.OutgoingMessage} req http request object
25
+ * @param {http.IncomingMessage} res http response object
26
+ * @param {rewriteCondition} rewriteCondition function which is called to determine whether the response should be rewritten
27
+ * @param {rewriteContent} rewriteContent function to be called to modify the HTML document
28
+ * @returns {void}
29
+ */
30
+ module.exports = async function rewriteHTML(req, res, rewriteCondition, rewriteContent) {
31
+ // rewriteCondition and rewriteContent function must be available
32
+ if (typeof rewriteCondition !== "function" && typeof rewriteContent !== "function") {
33
+ return;
34
+ }
35
+
36
+ // disable the compression for loading html-related content (via accept header)
37
+ const accept = req.headers["accept"]?.indexOf("html") !== -1;
38
+ if (accept) {
39
+ req.headers["accept-encoding"] = "identity";
40
+ }
41
+
42
+ // store the references to the origin response methods
43
+ const { writeHead, end } = res;
44
+
45
+ // buffer to store the received content in
46
+ const contentBuffer = [];
47
+
48
+ // remove the content-length header
49
+ res.writeHead = function () {
50
+ if (!rewriteCondition(res)) return end.apply(this, arguments);
51
+ res.removeHeader("content-length");
52
+ return writeHead.apply(this, arguments);
53
+ };
54
+
55
+ // intercepts the response end to parse the HTML content
56
+ res.end = function (content, encoding) {
57
+ if (!rewriteCondition(res)) return end.apply(this, arguments);
58
+
59
+ // store the last chunk in the content buffer
60
+ contentBuffer.push(content instanceof Buffer ? content.toString(encoding) : content);
61
+
62
+ // create the html content and parse it
63
+ let htmlContent = contentBuffer.join("");
64
+ const doc = HTMLParser.parse(htmlContent);
65
+
66
+ // now run the callback
67
+ rewriteContent(doc);
68
+
69
+ // update the html content
70
+ htmlContent = doc.toString();
71
+
72
+ // the rest is on express
73
+ end.call(res, htmlContent, encoding);
74
+ };
75
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cds-plugin-ui5",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "description": "A CAP server cds-plugin to inject the middlewares of all related UI5 tooling based projects.",
5
5
  "author": "Peter Muessig",
6
6
  "license": "Apache-2.0",
@@ -24,5 +24,5 @@
24
24
  "@sap/cds": ">=6.8.2",
25
25
  "express": ">=4.18.2"
26
26
  },
27
- "gitHead": "1f8272a1e1faa0559fd9e57b03da2ada256d23df"
27
+ "gitHead": "423a54e264aff78d664bc4f7a1aa2fcd30ce2142"
28
28
  }