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 +22 -0
- package/cds-plugin.js +32 -31
- package/lib/applyUI5Middleware.js +2 -2
- package/lib/createPatchedRouter.js +35 -22
- package/lib/rewriteHTML.js +75 -0
- package/package.json +2 -2
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
head.
|
|
81
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
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
|
-
//
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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 ${
|
|
47
|
+
title.innerHTML = `Index of ${contextPath}/`;
|
|
39
48
|
}
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
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?.
|
|
46
|
-
|
|
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
|
-
|
|
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.
|
|
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": "
|
|
27
|
+
"gitHead": "423a54e264aff78d664bc4f7a1aa2fcd30ce2142"
|
|
28
28
|
}
|