@ui5/server 3.0.0-alpha.3 → 3.0.0-alpha.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
@@ -2,7 +2,22 @@
2
2
  All notable changes to this project will be documented in this file.
3
3
  This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
4
4
 
5
- A list of unreleased changes can be found [here](https://github.com/SAP/ui5-server/compare/v3.0.0-alpha.3...HEAD).
5
+ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-server/compare/v3.0.0-alpha.4...HEAD).
6
+
7
+ <a name="v3.0.0-alpha.4"></a>
8
+ ## [v3.0.0-alpha.4] - 2022-10-24
9
+ ### Breaking Changes
10
+ - Transform to native ESM ([#501](https://github.com/SAP/ui5-server/issues/501)) [`05e3013`](https://github.com/SAP/ui5-server/commit/05e3013605e28e9ab5a785aa57616473d40e5710)
11
+
12
+ ### BREAKING CHANGE
13
+
14
+ This package has been transformed to native ESM. Therefore it no longer provides a CommonJS export.
15
+ If your project uses CommonJS, it needs to be converted to ESM or use a dynamic import.
16
+
17
+ For more information see also:
18
+ - https://sap.github.io/ui5-tooling/updates/migrate-v3/
19
+ - https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
20
+
6
21
 
7
22
  <a name="v3.0.0-alpha.3"></a>
8
23
  ## [v3.0.0-alpha.3] - 2022-07-27
@@ -275,6 +290,7 @@ Only Node.js v10 or higher is supported.
275
290
  <a name="v0.0.1"></a>
276
291
  ## v0.0.1 - 2018-06-06
277
292
 
293
+ [v3.0.0-alpha.4]: https://github.com/SAP/ui5-server/compare/v3.0.0-alpha.3...v3.0.0-alpha.4
278
294
  [v3.0.0-alpha.3]: https://github.com/SAP/ui5-server/compare/v3.0.0-alpha.2...v3.0.0-alpha.3
279
295
  [v3.0.0-alpha.2]: https://github.com/SAP/ui5-server/compare/v3.0.0-alpha.1...v3.0.0-alpha.2
280
296
  [v3.0.0-alpha.1]: https://github.com/SAP/ui5-server/compare/v3.0.0-alpha.0...v3.0.0-alpha.1
package/jsdoc.json CHANGED
@@ -3,12 +3,12 @@
3
3
  "allowUnknownTags": false
4
4
  },
5
5
  "source": {
6
- "include": ["README.md", "index.js"],
6
+ "include": ["README.md"],
7
7
  "includePattern": ".+\\.js$",
8
8
  "excludePattern": "(node_modules(\\\\|/))"
9
9
  },
10
10
  "plugins": [
11
- "./jsdoc-plugin"
11
+ "./jsdoc-plugin.cjs"
12
12
  ],
13
13
  "opts": {
14
14
  "encoding": "utf8",
@@ -1,20 +1,23 @@
1
- const middlewareRepository = require("./middlewareRepository");
2
- const MiddlewareUtil = require("./MiddlewareUtil");
1
+ import middlewareRepository from "./middlewareRepository.js";
2
+ import MiddlewareUtil from "./MiddlewareUtil.js";
3
3
  const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty);
4
4
 
5
5
  /**
6
- *
7
- * @typedef {object} middlewareResources
8
- * @property {module:@ui5/fs.AbstractReader} all Reader or Collection to read resources of the
6
+ * @private
7
+ * @typedef {object} MiddlewareResources
8
+ * @property {@ui5/fs.AbstractReader} all Reader or Collection to read resources of the
9
9
  * root project and its dependencies
10
- * @property {module:@ui5/fs.AbstractReader} rootProject Reader or Collection to read resources of
10
+ * @property {@ui5/fs.AbstractReader} rootProject Reader or Collection to read resources of
11
11
  * the project the server is started in
12
+ * @memberof @ui5/server/internal/MiddlewareManager
12
13
  */
13
14
 
14
15
  /**
16
+ * The MiddlewareManager
15
17
  *
16
- *
17
- * @memberof module:@ui5/server.middleware
18
+ * @private
19
+ * @class
20
+ * @alias @ui5/server/internal/MiddlewareManager
18
21
  */
19
22
  class MiddlewareManager {
20
23
  constructor({graph, resources, options = {
@@ -33,6 +36,14 @@ class MiddlewareManager {
33
36
  this.middlewareUtil = new MiddlewareUtil();
34
37
  }
35
38
 
39
+ /**
40
+ * Applies the middleware to
41
+ *
42
+ * @private
43
+ * @param {object} app The express application object
44
+ * @returns {Promise<Array<undefined>>} Promise resolving to an Array with a length of the number
45
+ * of added middlewares. The entries of the Array have a value of <code>undefined</code>.
46
+ */
36
47
  async applyMiddleware(app) {
37
48
  await this.addStandardMiddleware();
38
49
  await this.addCustomMiddleware();
@@ -43,6 +54,18 @@ class MiddlewareManager {
43
54
  });
44
55
  }
45
56
 
57
+ /**
58
+ * Adds the given middleware configuration
59
+ *
60
+ * @private
61
+ * @param {string} configuredMiddlewareName The name of the middleware
62
+ * @param {object} [options] The Options of the middleware
63
+ * @param {object} [options.customMiddleware] The custom middleware
64
+ * @param {Function} [options.wrapperCallback] Callback called when middleware is called
65
+ * @param {string} [options.mountPath="/"] The path hosting the middleware
66
+ * @param {string} [options.beforeMiddleware] The name of the middleware called before the added middleware
67
+ * @param {string} [options.afterMiddleware] The name of the middleware called after the added middleware
68
+ */
46
69
  async addMiddleware(configuredMiddlewareName, {
47
70
  customMiddleware, wrapperCallback, mountPath = "/",
48
71
  beforeMiddleware, afterMiddleware
@@ -51,7 +74,7 @@ class MiddlewareManager {
51
74
  if (customMiddleware) {
52
75
  middlewareCallback = customMiddleware;
53
76
  } else {
54
- const middlewareInfo = middlewareRepository.getMiddleware(configuredMiddlewareName);
77
+ const middlewareInfo = await middlewareRepository.getMiddleware(configuredMiddlewareName);
55
78
  if (wrapperCallback) {
56
79
  middlewareCallback = wrapperCallback(middlewareInfo);
57
80
  } else {
@@ -98,6 +121,12 @@ class MiddlewareManager {
98
121
  };
99
122
  }
100
123
 
124
+ /**
125
+ * Adds all registered standard middlewares
126
+ *
127
+ * @private
128
+ * @returns {Promise} Resolving to <code>undefined</code> once all standard middlewares are added
129
+ */
101
130
  async addStandardMiddleware() {
102
131
  await this.addMiddleware("csp", {
103
132
  wrapperCallback: ({middleware: cspModule}) => {
@@ -214,6 +243,12 @@ class MiddlewareManager {
214
243
  });
215
244
  }
216
245
 
246
+ /**
247
+ * Adds all registered custom middlewares
248
+ *
249
+ * @private
250
+ * @returns {Promise} Resolving to <code>undefined</code> once all custom middlewares are added
251
+ */
217
252
  async addCustomMiddleware() {
218
253
  const project = this.graph.getRoot();
219
254
  const projectCustomMiddleware = project.getCustomMiddleware();
@@ -238,7 +273,7 @@ class MiddlewareManager {
238
273
  `defines neither a "beforeMiddleware" nor an "afterMiddleware" parameter. One must be defined.`);
239
274
  }
240
275
  await this.addMiddleware(middlewareDef.name, {
241
- customMiddleware: ({resources, middlewareUtil}) => {
276
+ customMiddleware: async ({resources, middlewareUtil}) => {
242
277
  const customMiddleware = this.graph.getExtension(middlewareDef.name);
243
278
  const specVersion = customMiddleware.getSpecVersion();
244
279
  const options = {
@@ -254,7 +289,7 @@ class MiddlewareManager {
254
289
  // Supply interface to MiddlewareUtil instance starting with specVersion 2.0
255
290
  params.middlewareUtil = middlewareUtil.getInterface(specVersion);
256
291
  }
257
- return customMiddleware.getMiddleware()(params);
292
+ return (await customMiddleware.getMiddleware())(params);
258
293
  },
259
294
  mountPath: middlewareDef.mountPath,
260
295
  beforeMiddleware: middlewareDef.beforeMiddleware,
@@ -264,4 +299,4 @@ class MiddlewareManager {
264
299
  }
265
300
  }
266
301
 
267
- module.exports = MiddlewareManager;
302
+ export default MiddlewareManager;
@@ -1,3 +1,6 @@
1
+ import parseurl from "parseurl";
2
+ import mime from "mime-types";
3
+
1
4
  /**
2
5
  * Convenience functions for UI5 Server middleware.
3
6
  * An instance of this class is passed to every standard UI5 Server middleware.
@@ -8,7 +11,9 @@
8
11
  * version defined for the extension.
9
12
  *
10
13
  * @public
11
- * @memberof module:@ui5/server.middleware
14
+ * @class
15
+ * @alias @ui5/server/middleware/MiddlewareUtil
16
+ * @hideconstructor
12
17
  */
13
18
  class MiddlewareUtil {
14
19
  /**
@@ -54,7 +59,6 @@ class MiddlewareUtil {
54
59
  * @public
55
60
  */
56
61
  getPathname(req) {
57
- const parseurl = require("parseurl");
58
62
  let {pathname} = parseurl(req);
59
63
  pathname = decodeURIComponent(pathname);
60
64
  return pathname;
@@ -75,7 +79,7 @@ class MiddlewareUtil {
75
79
  * @property {string} type Detected content-type for the given resource path
76
80
  * @property {string} charset Default charset for the detected content-type
77
81
  * @property {string} contentType Calculated content-type header value
78
- * @memberof module:@ui5/server.middleware.MiddlewareUtil
82
+ * @memberof @ui5/server/middleware/MiddlewareUtil
79
83
  */
80
84
  /**
81
85
  * Returns MIME information derived from a given resource path.
@@ -84,11 +88,10 @@ class MiddlewareUtil {
84
88
  * <b>Specification Version 2.0 and above</b>.
85
89
  *
86
90
  * @param {object} resourcePath
87
- * @returns {module:@ui5/server.middleware.MiddlewareUtil.MimeInfo}
91
+ * @returns {@ui5/server/middleware/MiddlewareUtil.MimeInfo}
88
92
  * @public
89
93
  */
90
94
  getMimeInfo(resourcePath) {
91
- const mime = require("mime-types");
92
95
  const type = mime.lookup(resourcePath) || "application/octet-stream";
93
96
  const charset = mime.charset(type);
94
97
  return {
@@ -99,4 +102,4 @@ class MiddlewareUtil {
99
102
  }
100
103
  }
101
104
 
102
- module.exports = MiddlewareUtil;
105
+ export default MiddlewareUtil;
@@ -1,4 +1,4 @@
1
- const ui5connect = require("connect-openui5");
1
+ import ui5connect from "connect-openui5";
2
2
 
3
3
  function createMiddleware() {
4
4
  return ui5connect.proxy({
@@ -6,4 +6,4 @@ function createMiddleware() {
6
6
  });
7
7
  }
8
8
 
9
- module.exports = createMiddleware;
9
+ export default createMiddleware;
@@ -1,8 +1,10 @@
1
- const parseurl = require("parseurl");
2
- const Router = require("router");
3
- const querystring = require("querystring");
1
+ import parseurl from "parseurl";
2
+ import Router from "router";
3
+ import querystring from "node:querystring";
4
+ import logger from "@ui5/logger";
5
+ import bodyParser from "body-parser";
4
6
 
5
- const log = require("@ui5/logger").getLogger("server:middleware:csp");
7
+ const log = logger.getLogger("server:middleware:csp");
6
8
 
7
9
  const HEADER_CONTENT_SECURITY_POLICY = "Content-Security-Policy";
8
10
  const HEADER_CONTENT_SECURITY_POLICY_REPORT_ONLY = "Content-Security-Policy-Report-Only";
@@ -77,7 +79,6 @@ function createMiddleware(sCspUrlParameterName, oConfig) {
77
79
  // .csplog
78
80
  // body parser is required to parse csp-report in body (json)
79
81
  if (serveCSPReports) {
80
- const bodyParser = require("body-parser");
81
82
  router.post("/.ui5/csp/report.csplog", bodyParser.json({type: "application/csp-report"}));
82
83
  }
83
84
  router.post("/.ui5/csp/report.csplog", function(req, res, next) {
@@ -196,4 +197,4 @@ function createMiddleware(sCspUrlParameterName, oConfig) {
196
197
  return router;
197
198
  }
198
199
 
199
- module.exports = createMiddleware;
200
+ export default createMiddleware;
@@ -112,4 +112,4 @@ function createMiddleware({resources}) {
112
112
  };
113
113
  }
114
114
 
115
- module.exports = createMiddleware;
115
+ export default createMiddleware;
@@ -1,34 +1,55 @@
1
1
  const middlewareInfos = {
2
2
  compression: {path: "compression"},
3
3
  cors: {path: "cors"},
4
- csp: {path: "./csp"},
5
- serveResources: {path: "./serveResources"},
6
- serveIndex: {path: "./serveIndex"},
7
- discovery: {path: "./discovery"},
8
- versionInfo: {path: "./versionInfo"},
9
- connectUi5Proxy: {path: "./connectUi5Proxy"},
10
- serveThemes: {path: "./serveThemes"},
11
- testRunner: {path: "./testRunner"},
12
- nonReadRequests: {path: "./nonReadRequests"}
4
+ csp: {path: "./csp.js"},
5
+ serveResources: {path: "./serveResources.js"},
6
+ serveIndex: {path: "./serveIndex.js"},
7
+ discovery: {path: "./discovery.js"},
8
+ versionInfo: {path: "./versionInfo.js"},
9
+ connectUi5Proxy: {path: "./connectUi5Proxy.js"},
10
+ serveThemes: {path: "./serveThemes.js"},
11
+ testRunner: {path: "./testRunner.js"},
12
+ nonReadRequests: {path: "./nonReadRequests.js"}
13
13
  };
14
14
 
15
- function getMiddleware(middlewareName) {
15
+ // see @ui5/server/internal/middlewareRepository#getMiddleware
16
+ async function getMiddleware(middlewareName) {
16
17
  const middlewareInfo = middlewareInfos[middlewareName];
17
18
 
18
19
  if (!middlewareInfo) {
19
20
  throw new Error(`middlewareRepository: Unknown Middleware ${middlewareName}`);
20
21
  }
21
22
  try {
22
- const middleware = require(middlewareInfo.path);
23
+ const {default: middleware} = await import(middlewareInfo.path);
23
24
  return {
24
25
  middleware
25
26
  };
26
27
  } catch (err) {
27
28
  throw new Error(
28
- `middlewareRepository: Failed to require middleware module for ${middlewareName}: ${err.message}`);
29
+ `middlewareRepository: Failed to require middleware module for ${middlewareName}:\n${err.stack}`);
29
30
  }
30
31
  }
32
+ /**
33
+ * @private
34
+ * @typedef {object} module:@ui5/server/internal/middlewareRepository~Middleware
35
+ * @property {object} middleware The middleware
36
+ */
31
37
 
32
- module.exports = {
38
+ /**
39
+ * @private
40
+ * @module @ui5/server/internal/middlewareRepository
41
+ * @borrows getMiddleware as getMiddleware
42
+ */
43
+ export default {
44
+
45
+ /**
46
+ * Determines the desired middleware
47
+ *
48
+ * @private
49
+ * @static
50
+ * @function
51
+ * @param {string} middlewareName The name of the middleware
52
+ * @returns {module:@ui5/server/internal/middlewareRepository~Middleware} The middleware
53
+ */
33
54
  getMiddleware: getMiddleware
34
55
  };
@@ -20,4 +20,4 @@ function createMiddleware() {
20
20
  };
21
21
  }
22
22
 
23
- module.exports = createMiddleware;
23
+ export default createMiddleware;
@@ -1,6 +1,7 @@
1
- const log = require("@ui5/logger").getLogger("server:middleware:serveIndex");
2
- const mime = require("mime-types");
3
- const serveIndex = require("./serveIndex/serveIndex.js");
1
+ import logger from "@ui5/logger";
2
+ const log = logger.getLogger("server:middleware:serveIndex");
3
+ import mime from "mime-types";
4
+ import serveIndex from "./serveIndex/serveIndex.cjs";
4
5
 
5
6
  const KB = 1024;
6
7
  const MB = KB * KB;
@@ -120,4 +121,4 @@ function createMiddleware({resources, middlewareUtil, simpleIndex = false, showH
120
121
  };
121
122
  }
122
123
 
123
- module.exports = createMiddleware;
124
+ export default createMiddleware;
@@ -1,7 +1,8 @@
1
- const log = require("@ui5/logger").getLogger("server:middleware:serveResources");
2
- const replaceStream = require("replacestream");
3
- const etag = require("etag");
4
- const fresh = require("fresh");
1
+ import logger from "@ui5/logger";
2
+ const log = logger.getLogger("server:middleware:serveResources");
3
+ import replaceStream from "replacestream";
4
+ import etag from "etag";
5
+ import fresh from "fresh";
5
6
 
6
7
  const rProperties = /\.properties$/i;
7
8
  const rReplaceVersion = /\.(library|js|json)$/i;
@@ -33,14 +34,16 @@ function createMiddleware({resources, middlewareUtil}) {
33
34
  return;
34
35
  }
35
36
  if (log.isLevelEnabled("verbose")) {
36
- const treeify = require("treeify");
37
+ const {
38
+ default: treeify
39
+ } = await import("treeify");
37
40
  log.verbose("\n" + treeify.asTree(resource.getPathTree()));
38
41
  }
39
42
 
40
43
  const resourcePath = resource.getPath();
41
44
  if (rProperties.test(resourcePath)) {
42
45
  // Special handling for *.properties files escape non ascii characters.
43
- const nonAsciiEscaper = require("@ui5/builder").processors.nonAsciiEscaper;
46
+ const {default: nonAsciiEscaper} = await import("@ui5/builder/processors/nonAsciiEscaper");
44
47
  const project = resource.getProject();
45
48
  let propertiesFileSourceEncoding = project?.getPropertiesFileSourceEncoding();
46
49
 
@@ -98,4 +101,4 @@ function createMiddleware({resources, middlewareUtil}) {
98
101
  };
99
102
  }
100
103
 
101
- module.exports = createMiddleware;
104
+ export default createMiddleware;
@@ -1,9 +1,9 @@
1
- const themeBuilder = require("@ui5/builder").processors.themeBuilder;
2
- const fsInterface = require("@ui5/fs").fsInterface;
3
- const {basename, dirname} = require("path").posix;
4
- const etag = require("etag");
5
- const fresh = require("fresh");
6
- const parseurl = require("parseurl");
1
+ import {ThemeBuilder} from "@ui5/builder/processors/themeBuilder";
2
+ import fsInterface from "@ui5/fs/fsInterface";
3
+ import {basename, dirname} from "node:path/posix";
4
+ import etag from "etag";
5
+ import fresh from "fresh";
6
+ import parseurl from "parseurl";
7
7
 
8
8
  function isFresh(req, res) {
9
9
  return fresh(req.headers, {
@@ -40,7 +40,7 @@ const themeResources = [
40
40
  * @returns {Function} Returns a server middleware closure.
41
41
  */
42
42
  function createMiddleware({resources, middlewareUtil}) {
43
- const builder = new themeBuilder.ThemeBuilder({
43
+ const builder = new ThemeBuilder({
44
44
  fs: fsInterface(resources.all)
45
45
  });
46
46
  const buildOptions = {};
@@ -120,4 +120,4 @@ function createMiddleware({resources, middlewareUtil}) {
120
120
  };
121
121
  }
122
122
 
123
- module.exports = createMiddleware;
123
+ export default createMiddleware;
@@ -1,10 +1,11 @@
1
- const {promisify} = require("util");
2
- const fs = require("graceful-fs");
1
+ import {promisify} from "node:util";
2
+ import fs from "graceful-fs";
3
3
  const readFile = promisify(fs.readFile);
4
- const path = require("path");
5
- const mime = require("mime-types");
6
- const parseurl = require("parseurl");
7
- const log = require("@ui5/logger").getLogger("server:middleware:testRunner");
4
+ import {fileURLToPath} from "node:url";
5
+ import mime from "mime-types";
6
+ import parseurl from "parseurl";
7
+ import logger from "@ui5/logger";
8
+ const log = logger.getLogger("server:middleware:testRunner");
8
9
 
9
10
  const testRunnerResourceRegEx = /\/test-resources\/sap\/ui\/qunit\/(testrunner\.(html|css)|TestRunner.js)$/;
10
11
  const resourceCache = {};
@@ -40,7 +41,8 @@ function createMiddleware({resources}) {
40
41
  log.verbose(`Serving ${pathname}`);
41
42
  let pResource;
42
43
  if (!resourceCache[pathname]) {
43
- pResource = readFile(path.join(__dirname, "testRunner", resourceName), {encoding: "utf8"});
44
+ const filePath = fileURLToPath(new URL(`./testRunner/${resourceName}`, import.meta.url));
45
+ pResource = readFile(filePath, {encoding: "utf8"});
44
46
  resourceCache[pathname] = pResource;
45
47
  } else {
46
48
  pResource = resourceCache[pathname];
@@ -57,4 +59,4 @@ function createMiddleware({resources}) {
57
59
  };
58
60
  }
59
61
 
60
- module.exports = createMiddleware;
62
+ export default createMiddleware;
@@ -1,5 +1,5 @@
1
- const createVersionInfoProcessor = require("@ui5/builder").processors.versionInfoGenerator;
2
- const createManifestProcessor = require("@ui5/builder").processors.manifestCreator;
1
+ import createVersionInfoProcessor from "@ui5/builder/processors/versionInfoGenerator";
2
+ import createManifestProcessor from "@ui5/builder/processors/manifestCreator";
3
3
 
4
4
  const MANIFEST_JSON = "manifest.json";
5
5
 
@@ -8,8 +8,8 @@ const MANIFEST_JSON = "manifest.json";
8
8
  *
9
9
  * @module @ui5/server/middleware/versionInfo
10
10
  * @param {object} parameters Parameters
11
- * @param {module:@ui5/server.middleware.MiddlewareManager.middlewareResources} parameters.resources Parameters
12
- * @param {module:@ui5/project.graph.ProjectGraph} parameters.graph Project graph
11
+ * @param {@ui5/server.middleware.MiddlewareManager.middlewareResources} parameters.resources Parameters
12
+ * @param {@ui5/project.graph.ProjectGraph} parameters.graph Project graph
13
13
  * @returns {Function} Returns a server middleware closure.
14
14
  */
15
15
  function createMiddleware({resources, graph}) {
@@ -74,4 +74,4 @@ function createMiddleware({resources, graph}) {
74
74
  };
75
75
  }
76
76
 
77
- module.exports = createMiddleware;
77
+ export default createMiddleware;
package/lib/server.js CHANGED
@@ -1,11 +1,13 @@
1
- const express = require("express");
2
- const portscanner = require("portscanner");
1
+ import express from "express";
2
+ import portscanner from "portscanner";
3
+ import MiddlewareManager from "./middleware/MiddlewareManager.js";
4
+ import {createReaderCollection} from "@ui5/fs/resourceFactory";
5
+ import ReaderCollectionPrioritized from "@ui5/fs/ReaderCollectionPrioritized";
3
6
 
4
- const MiddlewareManager = require("./middleware/MiddlewareManager");
5
-
6
- const ui5Fs = require("@ui5/fs");
7
- const resourceFactory = ui5Fs.resourceFactory;
8
- const ReaderCollectionPrioritized = ui5Fs.ReaderCollectionPrioritized;
7
+ /**
8
+ * @public
9
+ * @module @ui5/server
10
+ */
9
11
 
10
12
  /**
11
13
  * Returns a promise resolving by starting the server.
@@ -79,13 +81,14 @@ function _listen(app, port, changePortIfInUse, acceptRemoteConnections) {
79
81
  * @param {object} parameters.app The original express application
80
82
  * @param {string} parameters.key Path to private key to be used for https
81
83
  * @param {string} parameters.cert Path to certificate to be used for for https
82
- * @returns {object} The express application with SSL support
84
+ * @returns {Promise<object>} The express application with SSL support
83
85
  * @private
84
86
  */
85
- function _addSsl({app, key, cert}) {
87
+ async function _addSsl({app, key, cert}) {
86
88
  // Using spdy as http2 server as the native http2 implementation
87
89
  // from Node v8.4.0 doesn't seem to work with express
88
- return require("spdy").createServer({cert, key}, app);
90
+ const {default: spdy} = await import("spdy");
91
+ return spdy.createServer({cert, key}, app);
89
92
  }
90
93
 
91
94
 
@@ -93,7 +96,7 @@ function _addSsl({app, key, cert}) {
93
96
  * SAP target CSP middleware options
94
97
  *
95
98
  * @public
96
- * @typedef {object} module:@ui5/server.server.SAPTargetCSPOptions
99
+ * @typedef {object} module:@ui5/server.SAPTargetCSPOptions
97
100
  * @property {string} [defaultPolicy="sap-target-level-1"]
98
101
  * @property {string} [defaultPolicyIsReportOnly=true]
99
102
  * @property {string} [defaultPolicy2="sap-target-level-2"]
@@ -103,94 +106,87 @@ function _addSsl({app, key, cert}) {
103
106
 
104
107
 
105
108
  /**
109
+ * Start a server for the given project (sub-)tree.
110
+ *
106
111
  * @public
107
- * @namespace
108
- * @alias module:@ui5/server.server
112
+ * @param {@ui5/project/graph/ProjectGraph} graph Project graph
113
+ * @param {object} options Options
114
+ * @param {number} options.port Port to listen to
115
+ * @param {boolean} [options.changePortIfInUse=false] If true, change the port if it is already in use
116
+ * @param {boolean} [options.h2=false] Whether HTTP/2 should be used - defaults to <code>http</code>
117
+ * @param {string} [options.key] Path to private key to be used for https
118
+ * @param {string} [options.cert] Path to certificate to be used for for https
119
+ * @param {boolean} [options.simpleIndex=false] Use a simplified view for the server directory listing
120
+ * @param {boolean} [options.acceptRemoteConnections=false] If true, listens to remote connections and
121
+ * not only to localhost connections
122
+ * @param {boolean|module:@ui5/server.SAPTargetCSPOptions} [options.sendSAPTargetCSP=false]
123
+ * If set to <code>true</code> or an object, then the default (or configured)
124
+ * set of security policies that SAP and UI5 aim for (AKA 'target policies'),
125
+ * are send for any requested <code>*.html</code> file
126
+ * @param {boolean} [options.serveCSPReports=false] Enable CSP reports serving for request url
127
+ * '/.ui5/csp/csp-reports.json'
128
+ * @returns {Promise<object>} Promise resolving once the server is listening.
129
+ * It resolves with an object containing the <code>port</code>,
130
+ * <code>h2</code>-flag and a <code>close</code> function,
131
+ * which can be used to stop the server.
109
132
  */
110
- module.exports = {
111
- /**
112
- * Start a server for the given project (sub-)tree.
113
- *
114
- * @public
115
- * @param {module:@ui5/project.graph.ProjectGraph} graph Project graph
116
- * @param {object} options Options
117
- * @param {number} options.port Port to listen to
118
- * @param {boolean} [options.changePortIfInUse=false] If true, change the port if it is already in use
119
- * @param {boolean} [options.h2=false] Whether HTTP/2 should be used - defaults to <code>http</code>
120
- * @param {string} [options.key] Path to private key to be used for https
121
- * @param {string} [options.cert] Path to certificate to be used for for https
122
- * @param {boolean} [options.simpleIndex=false] Use a simplified view for the server directory listing
123
- * @param {boolean} [options.acceptRemoteConnections=false] If true, listens to remote connections and
124
- * not only to localhost connections
125
- * @param {boolean|module:@ui5/server.server.SAPTargetCSPOptions} [options.sendSAPTargetCSP=false]
126
- * If set to <code>true</code> or an object, then the default (or configured)
127
- * set of security policies that SAP and UI5 aim for (AKA 'target policies'),
128
- * are send for any requested <code>*.html</code> file
129
- * @param {boolean} [options.serveCSPReports=false] Enable CSP reports serving for request url
130
- * '/.ui5/csp/csp-reports.json'
131
- * @returns {Promise<object>} Promise resolving once the server is listening.
132
- * It resolves with an object containing the <code>port</code>,
133
- * <code>h2</code>-flag and a <code>close</code> function,
134
- * which can be used to stop the server.
135
- */
136
- async serve(graph, {
137
- port: requestedPort, changePortIfInUse = false, h2 = false, key, cert,
138
- acceptRemoteConnections = false, sendSAPTargetCSP = false, simpleIndex = false, serveCSPReports = false
139
- }) {
140
- const rootProject = graph.getRoot();
141
-
142
- const readers = [];
143
- await graph.traverseBreadthFirst(async function({project: dep}) {
144
- if (dep.getName() === rootProject.getName()) {
145
- // Ignore root project
146
- return;
147
- }
148
- readers.push(dep.getReader({style: "runtime"}));
149
- });
150
-
151
- const dependencies = resourceFactory.createReaderCollection({
152
- name: `Dependency reader collection for project ${rootProject.getName()}`,
153
- readers
154
- });
155
-
156
- const rootReader = rootProject.getReader({style: "runtime"});
133
+ export async function serve(graph, {
134
+ port: requestedPort, changePortIfInUse = false, h2 = false, key, cert,
135
+ acceptRemoteConnections = false, sendSAPTargetCSP = false, simpleIndex = false, serveCSPReports = false
136
+ }) {
137
+ const rootProject = graph.getRoot();
138
+
139
+ const readers = [];
140
+ await graph.traverseBreadthFirst(async function({project: dep}) {
141
+ if (dep.getName() === rootProject.getName()) {
142
+ // Ignore root project
143
+ return;
144
+ }
145
+ readers.push(await dep.getReader({style: "runtime"}));
146
+ });
157
147
 
158
- // TODO change to ReaderCollection once duplicates are sorted out
159
- const combo = new ReaderCollectionPrioritized({
160
- name: "server - prioritize workspace over dependencies",
161
- readers: [rootReader, dependencies]
162
- });
163
- const resources = {
164
- rootProject: rootReader,
165
- dependencies: dependencies,
166
- all: combo
167
- };
168
-
169
- const middlewareManager = new MiddlewareManager({
170
- graph,
171
- resources,
172
- options: {
173
- sendSAPTargetCSP,
174
- serveCSPReports,
175
- simpleIndex
176
- }
177
- });
148
+ const dependencies = createReaderCollection({
149
+ name: `Dependency reader collection for project ${rootProject.getName()}`,
150
+ readers
151
+ });
178
152
 
179
- let app = express();
180
- await middlewareManager.applyMiddleware(app);
153
+ const rootReader = await rootProject.getReader({style: "runtime"});
181
154
 
182
- if (h2) {
183
- app = _addSsl({app, key, cert});
155
+ // TODO change to ReaderCollection once duplicates are sorted out
156
+ const combo = new ReaderCollectionPrioritized({
157
+ name: "server - prioritize workspace over dependencies",
158
+ readers: [rootReader, dependencies]
159
+ });
160
+ const resources = {
161
+ rootProject: rootReader,
162
+ dependencies: dependencies,
163
+ all: combo
164
+ };
165
+
166
+ const middlewareManager = new MiddlewareManager({
167
+ graph,
168
+ resources,
169
+ options: {
170
+ sendSAPTargetCSP,
171
+ serveCSPReports,
172
+ simpleIndex
184
173
  }
174
+ });
185
175
 
186
- const {port, server} = await _listen(app, requestedPort, changePortIfInUse, acceptRemoteConnections);
176
+ let app = express();
177
+ await middlewareManager.applyMiddleware(app);
187
178
 
188
- return {
189
- h2,
190
- port,
191
- close: function(callback) {
192
- server.close(callback);
193
- }
194
- };
179
+ if (h2) {
180
+ app = await _addSsl({app, key, cert});
195
181
  }
196
- };
182
+
183
+ const {port, server} = await _listen(app, requestedPort, changePortIfInUse, acceptRemoteConnections);
184
+
185
+ return {
186
+ h2,
187
+ port,
188
+ close: function(callback) {
189
+ server.close(callback);
190
+ }
191
+ };
192
+ }
package/lib/sslUtil.js CHANGED
@@ -1,58 +1,63 @@
1
- const os = require("os");
2
- const fs = require("fs");
3
- const log = require("@ui5/logger").getLogger("server:sslUtil");
4
- const {promisify} = require("util");
1
+ import os from "node:os";
2
+ import fs from "node:fs";
3
+ import logger from "@ui5/logger";
4
+ const log = logger.getLogger("server:sslUtil");
5
+ import {promisify} from "node:util";
5
6
 
6
7
  const stat = promisify(fs.stat);
7
- const path = require("path");
8
+ import path from "node:path";
8
9
 
9
10
  const readFile = promisify(fs.readFile);
10
11
  const writeFile = promisify(fs.writeFile);
11
- const makeDir = require("make-dir");
12
12
 
13
- const sslUtil = {
14
- /**
15
- * Creates a new SSL certificate or validates an existing one.
16
- *
17
- * @module @ui5/server/sslUtil
18
- * @param {string} [keyPath=$HOME/.ui5/server/server.key] Path to private key to be used for https.
19
- * Defaults to <code>$HOME/.ui5/server/server.key</code>
20
- * @param {string} [certPath=$HOME/.ui5/server/server.crt] Path to certificate to be used for for https.
21
- * Defaults to <code>$HOME/.ui5/server/server.crt</codee>
22
- * @returns {Promise<object>} Resolves with an sslObject containing <code>cert</code> and <code>key</code>
23
- */
24
- getSslCertificate: function(
25
- keyPath = path.join(os.homedir(), ".ui5/server/server.key"),
26
- certPath = path.join(os.homedir(), ".ui5/server/server.crt")
27
- ) {
28
- // checks the certificates if they are present
29
- return Promise.all([
30
- fileExists(keyPath).then((bExists) => {
31
- if (!bExists) {
32
- log.verbose(`No SSL private key found at ${keyPath}`);
33
- return false;
34
- }
35
- return readFile(keyPath);
36
- }),
37
- fileExists(certPath).then((bExists) => {
38
- if (!bExists) {
39
- log.verbose(`No SSL certificate found at ${certPath}`);
40
- return false;
41
- }
42
- return readFile(certPath);
43
- })
44
- ]).then(function([key, cert]) {
45
- if (key && cert) {
46
- return {key, cert};
13
+
14
+ /**
15
+ * @private
16
+ * @module @ui5/server/internal/sslUtil
17
+ */
18
+
19
+ /**
20
+ * Creates a new SSL certificate or validates an existing one.
21
+ *
22
+ * @private
23
+ * @static
24
+ * @param {string} [keyPath=$HOME/.ui5/server/server.key] Path to private key to be used for https.
25
+ * Defaults to <code>$HOME/.ui5/server/server.key</code>
26
+ * @param {string} [certPath=$HOME/.ui5/server/server.crt] Path to certificate to be used for for https.
27
+ * Defaults to <code>$HOME/.ui5/server/server.crt</codee>
28
+ * @returns {Promise<object>} Resolves with an sslObject containing <code>cert</code> and <code>key</code>
29
+ */
30
+ export function getSslCertificate(
31
+ keyPath = path.join(os.homedir(), ".ui5/server/server.key"),
32
+ certPath = path.join(os.homedir(), ".ui5/server/server.crt")
33
+ ) {
34
+ // checks the certificates if they are present
35
+ return Promise.all([
36
+ fileExists(keyPath).then((bExists) => {
37
+ if (!bExists) {
38
+ log.verbose(`No SSL private key found at ${keyPath}`);
39
+ return false;
47
40
  }
48
- return createAndInstallCertificate(keyPath, certPath);
49
- });
50
- }
51
- };
41
+ return readFile(keyPath);
42
+ }),
43
+ fileExists(certPath).then((bExists) => {
44
+ if (!bExists) {
45
+ log.verbose(`No SSL certificate found at ${certPath}`);
46
+ return false;
47
+ }
48
+ return readFile(certPath);
49
+ })
50
+ ]).then(function([key, cert]) {
51
+ if (key && cert) {
52
+ return {key, cert};
53
+ }
54
+ return createAndInstallCertificate(keyPath, certPath);
55
+ });
56
+ }
52
57
 
53
58
 
54
59
  async function createAndInstallCertificate(keyPath, certPath) {
55
- const yesno = require("yesno");
60
+ const {default: yesno} = await import("yesno");
56
61
 
57
62
  const ok = await yesno({
58
63
  question: "No SSL certificates found. " +
@@ -65,7 +70,7 @@ async function createAndInstallCertificate(keyPath, certPath) {
65
70
  }
66
71
 
67
72
  // In case certificate is not found, create a self-signed one and put it into the user's trust store
68
- const devCert = require("devcert-sanscache");
73
+ const {default: devCert} = await import("devcert-sanscache");
69
74
 
70
75
  // Inform end user about entering his root password (needed for importing
71
76
  // the created certificate into the system)
@@ -81,6 +86,9 @@ async function createAndInstallCertificate(keyPath, certPath) {
81
86
  }
82
87
 
83
88
  const {key, cert} = await devCert("UI5Tooling");
89
+
90
+ const {default: makeDir} = await import("make-dir");
91
+
84
92
  await Promise.all([
85
93
  // Write certificates to the ui5 certificate folder
86
94
  // such that they are used by default upon next startup
@@ -99,5 +107,3 @@ function fileExists(filePath) {
99
107
  }
100
108
  });
101
109
  }
102
-
103
- module.exports = sslUtil;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ui5/server",
3
- "version": "3.0.0-alpha.3",
3
+ "version": "3.0.0-alpha.4",
4
4
  "description": "UI5 Tooling - Server",
5
5
  "author": {
6
6
  "name": "SAP SE",
@@ -16,7 +16,14 @@
16
16
  "development",
17
17
  "tool"
18
18
  ],
19
- "main": "index.js",
19
+ "type": "module",
20
+ "exports": {
21
+ ".": "./lib/server.js",
22
+ "./internal/sslUtil": "./lib/sslUtil.js",
23
+ "./internal/middlewareRepository": "./lib/middleware/middlewareRepository.js",
24
+ "./internal/MiddlewareManager": "./lib/middleware/MiddlewareManager.js",
25
+ "./package.json": "./package.json"
26
+ },
20
27
  "engines": {
21
28
  "node": ">= 16.13.2",
22
29
  "npm": ">= 8"
@@ -27,11 +34,11 @@
27
34
  "lint": "eslint ./",
28
35
  "unit": "rimraf test/tmp && ava",
29
36
  "unit-verbose": "rimraf test/tmp && cross-env UI5_LOG_LVL=verbose ava --verbose --serial",
30
- "unit-watch": "rimraf test/tmp && ava --watch",
31
- "unit-nyan": "rimraf test/tmp && ava --tap | tnyan",
32
- "unit-xunit": "rimraf test/tmp && ava --tap | tap-xunit --dontUseCommentsAsTestNames=true > test-results.xml",
37
+ "unit-watch": "npm run unit -- --watch",
38
+ "unit-nyan": "npm run unit -- --tap | tnyan",
39
+ "unit-xunit": "rimraf test/tmp && ava --node-arguments=\"--experimental-loader=@istanbuljs/esm-loader-hook\" --tap | tap-xunit --dontUseCommentsAsTestNames=true > test-results.xml",
33
40
  "unit-inspect": "cross-env UI5_LOG_LVL=verbose ava debug --break",
34
- "coverage": "nyc npm run unit",
41
+ "coverage": "rimraf test/tmp && nyc ava --node-arguments=\"--experimental-loader=@istanbuljs/esm-loader-hook\"",
35
42
  "coverage-xunit": "nyc --reporter=text --reporter=text-summary --reporter=cobertura npm run unit-xunit",
36
43
  "jsdoc": "npm run jsdoc-generate && open-cli jsdocs/index.html",
37
44
  "jsdoc-generate": "jsdoc -c ./jsdoc.json -t $(node -p 'path.dirname(require.resolve(\"docdash\"))') ./lib/ || (echo 'Error during JSDoc generation! Check log.' && exit 1)",
@@ -40,10 +47,9 @@
40
47
  "version": "git-chglog --sort semver --next-tag v$npm_package_version -o CHANGELOG.md && git add CHANGELOG.md",
41
48
  "postversion": "git push --follow-tags",
42
49
  "release-note": "git-chglog --sort semver -c .chglog/release-config.yml v$npm_package_version",
43
- "depcheck": "depcheck --ignores docdash,compression,cors"
50
+ "depcheck": "depcheck --ignores @ui5/server,docdash,compression,cors,@istanbuljs/esm-loader-hook --parsers='**/*.js:es6,**/*.cjs:es6'"
44
51
  },
45
52
  "files": [
46
- "index.js",
47
53
  "CHANGELOG.md",
48
54
  "CONTRIBUTING.md",
49
55
  "jsdoc.json",
@@ -57,6 +63,10 @@
57
63
  ],
58
64
  "ignoredByWatcher": [
59
65
  "test/tmp/**"
66
+ ],
67
+ "nodeArguments": [
68
+ "--loader=esmock",
69
+ "--no-warnings"
60
70
  ]
61
71
  },
62
72
  "nyc": {
@@ -71,8 +81,8 @@
71
81
  "jsdocs/**",
72
82
  "coverage/**",
73
83
  "test/**",
74
- ".eslintrc.js",
75
- "jsdoc-plugin.js"
84
+ ".eslintrc.cjs",
85
+ "jsdoc-plugin.cjs"
76
86
  ],
77
87
  "check-coverage": true,
78
88
  "statements": 90,
@@ -105,9 +115,9 @@
105
115
  "url": "git@github.com:SAP/ui5-server.git"
106
116
  },
107
117
  "dependencies": {
108
- "@ui5/builder": "^3.0.0-alpha.9",
109
- "@ui5/fs": "^3.0.0-alpha.5",
110
- "@ui5/logger": "^3.0.1-alpha.1",
118
+ "@ui5/builder": "^3.0.0-alpha.12",
119
+ "@ui5/fs": "^3.0.0-alpha.7",
120
+ "@ui5/logger": "^3.0.1-alpha.3",
111
121
  "body-parser": "^1.19.1",
112
122
  "compression": "^1.7.4",
113
123
  "connect-openui5": "^0.10.2",
@@ -129,21 +139,23 @@
129
139
  "yesno": "^0.3.1"
130
140
  },
131
141
  "devDependencies": {
132
- "@ui5/project": "^3.0.0-alpha.6",
133
- "ava": "^3.15.0",
142
+ "@istanbuljs/esm-loader-hook": "^0.2.0",
143
+ "@ui5/project": "^3.0.0-alpha.10",
144
+ "ava": "^4.3.3",
134
145
  "chokidar-cli": "^3.0.0",
135
146
  "cross-env": "^7.0.3",
136
147
  "depcheck": "^1.4.3",
137
148
  "docdash": "^1.2.0",
138
149
  "eslint": "^8.7.0",
139
150
  "eslint-config-google": "^0.14.0",
151
+ "eslint-plugin-ava": "^13.0.2",
140
152
  "eslint-plugin-jsdoc": "^37.6.3",
153
+ "esmock": "^2.0.0",
141
154
  "jsdoc": "^3.6.7",
142
- "mock-require": "^3.0.3",
143
155
  "nyc": "^15.1.0",
144
156
  "open-cli": "^6.0.1",
145
157
  "rimraf": "^3.0.2",
146
- "sinon": "^11.1.2",
158
+ "sinon": "^14.0.0",
147
159
  "supertest": "^6.2.1",
148
160
  "tap-nyan": "^1.1.0",
149
161
  "tap-xunit": "^2.4.1"
package/index.js DELETED
@@ -1,35 +0,0 @@
1
- /**
2
- * @module @ui5/server
3
- * @public
4
- */
5
- module.exports = {
6
- /**
7
- * @type {import('./lib/server')}
8
- */
9
- server: "./lib/server",
10
- /**
11
- * @type {import('./lib/sslUtil')}
12
- */
13
- sslUtil: "./lib/sslUtil",
14
- /**
15
- * @type {import('./lib/middleware/middlewareRepository')}
16
- */
17
- middlewareRepository: "./lib/middleware/middlewareRepository"
18
- };
19
-
20
- function exportModules(exportRoot, modulePaths) {
21
- for (const moduleName of Object.keys(modulePaths)) {
22
- if (typeof modulePaths[moduleName] === "object") {
23
- exportRoot[moduleName] = {};
24
- exportModules(exportRoot[moduleName], modulePaths[moduleName]);
25
- } else {
26
- Object.defineProperty(exportRoot, moduleName, {
27
- get() {
28
- return require(modulePaths[moduleName]);
29
- }
30
- });
31
- }
32
- }
33
- }
34
-
35
- exportModules(module.exports, JSON.parse(JSON.stringify(module.exports)));