@ui5/server 3.0.0-beta.1 → 3.0.0-beta.3

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,16 @@
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-beta.1...HEAD).
5
+ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-server/compare/v3.0.0-beta.3...HEAD).
6
+
7
+ <a name="v3.0.0-beta.3"></a>
8
+ ## [v3.0.0-beta.3] - 2022-11-30
9
+
10
+ <a name="v3.0.0-beta.2"></a>
11
+ ## [v3.0.0-beta.2] - 2022-11-29
12
+ ### Features
13
+ - **MiddlewareUtil:** Add getProject/getDependencies/resourceFactory API to interface ([#547](https://github.com/SAP/ui5-server/issues/547)) [`ab28f78`](https://github.com/SAP/ui5-server/commit/ab28f789ba929ef1319b6e562267e9717cc9937b)
14
+
6
15
 
7
16
  <a name="v3.0.0-beta.1"></a>
8
17
  ## [v3.0.0-beta.1] - 2022-11-07
@@ -293,6 +302,8 @@ Only Node.js v10 or higher is supported.
293
302
  <a name="v0.0.1"></a>
294
303
  ## v0.0.1 - 2018-06-06
295
304
 
305
+ [v3.0.0-beta.3]: https://github.com/SAP/ui5-server/compare/v3.0.0-beta.2...v3.0.0-beta.3
306
+ [v3.0.0-beta.2]: https://github.com/SAP/ui5-server/compare/v3.0.0-beta.1...v3.0.0-beta.2
296
307
  [v3.0.0-beta.1]: https://github.com/SAP/ui5-server/compare/v3.0.0-alpha.4...v3.0.0-beta.1
297
308
  [v3.0.0-alpha.4]: https://github.com/SAP/ui5-server/compare/v3.0.0-alpha.3...v3.0.0-alpha.4
298
309
  [v3.0.0-alpha.3]: https://github.com/SAP/ui5-server/compare/v3.0.0-alpha.2...v3.0.0-alpha.3
@@ -1,5 +1,6 @@
1
1
  import middlewareRepository from "./middlewareRepository.js";
2
2
  import MiddlewareUtil from "./MiddlewareUtil.js";
3
+ import logger from "@ui5/logger";
3
4
  const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty);
4
5
 
5
6
  /**
@@ -20,20 +21,22 @@ const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty);
20
21
  * @alias @ui5/server/internal/MiddlewareManager
21
22
  */
22
23
  class MiddlewareManager {
23
- constructor({graph, resources, options = {
24
+ constructor({graph, rootProject, resources, options = {
24
25
  sendSAPTargetCSP: false,
25
26
  serveCSPReports: false
26
27
  }}) {
27
- if (!graph || !resources || !resources.all || !resources.rootProject || !resources.dependencies) {
28
+ if (!graph || !rootProject || !resources || !resources.all ||
29
+ !resources.rootProject || !resources.dependencies) {
28
30
  throw new Error("[MiddlewareManager]: One or more mandatory parameters not provided");
29
31
  }
30
32
  this.graph = graph;
33
+ this.rootProject = rootProject;
31
34
  this.resources = resources;
32
35
  this.options = options;
33
36
 
34
- this.middleware = {};
37
+ this.middleware = Object.create(null);
35
38
  this.middlewareExecutionOrder = [];
36
- this.middlewareUtil = new MiddlewareUtil();
39
+ this.middlewareUtil = new MiddlewareUtil({graph, project: rootProject});
37
40
  }
38
41
 
39
42
  /**
@@ -275,19 +278,22 @@ class MiddlewareManager {
275
278
  await this.addMiddleware(middlewareDef.name, {
276
279
  customMiddleware: async ({resources, middlewareUtil}) => {
277
280
  const customMiddleware = this.graph.getExtension(middlewareDef.name);
278
- const specVersion = customMiddleware.getSpecVersion();
279
- const options = {
280
- configuration: middlewareDef.configuration
281
+
282
+ const params = {
283
+ resources,
284
+ options: {
285
+ configuration: middlewareDef.configuration
286
+ }
281
287
  };
282
- const params = {resources, options};
283
- if (
284
- specVersion === "2.0" || specVersion === "2.1" ||
285
- specVersion === "2.2" || specVersion === "2.3" ||
286
- specVersion === "2.4" || specVersion === "2.5" ||
287
- specVersion === "2.6"
288
- ) {
289
- // Supply interface to MiddlewareUtil instance starting with specVersion 2.0
290
- params.middlewareUtil = middlewareUtil.getInterface(specVersion);
288
+
289
+ const specVersion = customMiddleware.getSpecVersion();
290
+ if (specVersion.gte("3.0")) {
291
+ params.options.middlewareName = middlewareDef.name;
292
+ params.log = logger.getGroupLogger(`server:custom-middleware:${middlewareDef.name}`);
293
+ }
294
+ const middlewareUtilInterface = middlewareUtil.getInterface(specVersion);
295
+ if (middlewareUtilInterface) {
296
+ params.middlewareUtil = middlewareUtilInterface;
291
297
  }
292
298
  return (await customMiddleware.getMiddleware())(params);
293
299
  },
@@ -1,5 +1,13 @@
1
1
  import parseurl from "parseurl";
2
2
  import mime from "mime-types";
3
+ import {
4
+ createReaderCollection,
5
+ createReaderCollectionPrioritized,
6
+ createResource,
7
+ createFilterReader,
8
+ createLinkReader,
9
+ createFlatReader
10
+ } from "@ui5/fs/resourceFactory";
3
11
 
4
12
  /**
5
13
  * Convenience functions for UI5 Server middleware.
@@ -17,33 +25,21 @@ import mime from "mime-types";
17
25
  */
18
26
  class MiddlewareUtil {
19
27
  /**
20
- * Get an interface to an instance of this class that only provides those functions
21
- * that are supported by the given custom middleware extension specification version.
22
28
  *
23
- * @param {string} specVersion Specification Version of custom middleware extension
24
- * @returns {object} An object with bound instance methods supported by the given specification version
29
+ * @param {object} parameters
30
+ * @param {@ui5/project/graph/ProjectGraph} parameters.graph Relevant ProjectGraph
31
+ * @param {@ui5/project/specifications/Project} parameters.project Project that is being served
32
+ * @public
25
33
  */
26
- getInterface(specVersion) {
27
- const baseInterface = {
28
- getPathname: this.getPathname.bind(this),
29
- getMimeInfo: this.getMimeInfo.bind(this)
30
- };
31
- switch (specVersion) {
32
- case "0.1":
33
- case "1.0":
34
- case "1.1":
35
- return undefined;
36
- case "2.0":
37
- case "2.1":
38
- case "2.2":
39
- case "2.3":
40
- case "2.4":
41
- case "2.5":
42
- case "2.6":
43
- return baseInterface;
44
- default:
45
- throw new Error(`MiddlewareUtil: Unknown or unsupported Specification Version ${specVersion}`);
34
+ constructor({graph, project}) {
35
+ if (!graph) {
36
+ throw new Error(`Missing parameter "graph"`);
37
+ }
38
+ if (!project) {
39
+ throw new Error(`Missing parameter "project"`);
46
40
  }
41
+ this._graph = graph;
42
+ this._project = project;
47
43
  }
48
44
 
49
45
  /**
@@ -100,6 +96,151 @@ class MiddlewareUtil {
100
96
  contentType: type + (charset ? "; charset=" + charset : "")
101
97
  };
102
98
  }
99
+ /**
100
+ * Specification Version-dependent [Project]{@link @ui5/project/specifications/Project} interface.
101
+ * For details on individual functions, see [Project]{@link @ui5/project/specifications/Project}
102
+ *
103
+ * @public
104
+ * @typedef {object} @ui5/project/build/helpers/MiddlewareUtill~ProjectInterface
105
+ * @property {Function} getType Get the project type
106
+ * @property {Function} getName Get the project name
107
+ * @property {Function} getVersion Get the project version
108
+ * @property {Function} getNamespace Get the project namespace
109
+ * @property {Function} getRootReader Get the project rootReader
110
+ * @property {Function} getReader Get the project reader
111
+ * @property {Function} getCustomConfiguration Get the project Custom Configuration
112
+ * @property {Function} isFrameworkProject Check whether the project is a UI5-Framework project
113
+ */
114
+
115
+ /**
116
+ * Retrieve a single project from the dependency graph
117
+ *
118
+ * </br></br>
119
+ * This method is only available to custom server middleware extensions defining
120
+ * <b>Specification Version 3.0 and above</b>.
121
+ *
122
+ * @param {string} [projectName] Name of the project to retrieve. Defaults to the project currently being built
123
+ * @returns {@ui5/project/build/helpers/MiddlewareUtill~ProjectInterface|undefined}
124
+ * project instance or undefined if the project is unknown to the graph
125
+ * @public
126
+ */
127
+ getProject(projectName) {
128
+ if (projectName) {
129
+ return this._graph.getProject(projectName);
130
+ }
131
+ return this._project;
132
+ }
133
+
134
+ /**
135
+ * Retrieve a list of direct dependencies of a given project from the dependency graph.
136
+ * Note that this list does not include transitive dependencies.
137
+ *
138
+ * </br></br>
139
+ * This method is only available to custom server middleware extensions defining
140
+ * <b>Specification Version 3.0 and above</b>.
141
+ *
142
+ * @param {string} [projectName] Name of the project to retrieve. Defaults to the project currently being built
143
+ * @returns {string[]} Names of all direct dependencies
144
+ * @throws {Error} If the requested project is unknown to the graph
145
+ * @public
146
+ */
147
+ getDependencies(projectName) {
148
+ return this._graph.getDependencies(projectName || this._project.getName());
149
+ }
150
+
151
+ /**
152
+ * Specification Version-dependent set of [@ui5/fs/resourceFactory]{@link @ui5/fs/resourceFactory}
153
+ * functions provided to middleware.
154
+ * For details on individual functions, see [@ui5/fs/resourceFactory]{@link @ui5/fs/resourceFactory}
155
+ *
156
+ * @public
157
+ * @typedef {object} @ui5/project/build/helpers/MiddlewareUtill~resourceFactory
158
+ * @property {Function} createResource Creates a [Resource]{@link @ui5/fs/Resource}.
159
+ * Accepts the same parameters as the [Resource]{@link @ui5/fs/Resource} constructor.
160
+ * @property {Function} createReaderCollection Creates a reader collection:
161
+ * [ReaderCollection]{@link @ui5/fs/ReaderCollection}
162
+ * @property {Function} createReaderCollectionPrioritized Creates a prioritized reader collection:
163
+ * [ReaderCollectionPrioritized]{@link @ui5/fs/ReaderCollectionPrioritized}
164
+ * @property {Function} createFilterReader
165
+ * Create a [Filter-Reader]{@link @ui5/fs/readers/Filter} with the given reader.
166
+ * @property {Function} createLinkReader
167
+ * Create a [Link-Reader]{@link @ui5/fs/readers/Filter} with the given reader.
168
+ * @property {Function} createFlatReader Create a [Link-Reader]{@link @ui5/fs/readers/Link}
169
+ * where all requests are prefixed with <code>/resources/<namespace></code>.
170
+ */
171
+
172
+ /**
173
+ * Provides limited access to [@ui5/fs/resourceFactory]{@link @ui5/fs/resourceFactory} functions
174
+ *
175
+ * </br></br>
176
+ * This attribute is only available to custom server middleware extensions defining
177
+ * <b>Specification Version 3.0 and above</b>.
178
+ *
179
+ * @type {@ui5/project/build/helpers/MiddlewareUtill~resourceFactory}
180
+ * @public
181
+ */
182
+ resourceFactory = {
183
+ createResource,
184
+ createReaderCollection,
185
+ createReaderCollectionPrioritized,
186
+ createFilterReader,
187
+ createLinkReader,
188
+ createFlatReader,
189
+ };
190
+
191
+ /**
192
+ * Get an interface to an instance of this class that only provides those functions
193
+ * that are supported by the given custom middleware extension specification version.
194
+ *
195
+ * @param {@ui5/project/specifications/SpecificationVersion} specVersion
196
+ * SpecVersionComparator instance of the custom server middleware
197
+ * @returns {object} An object with bound instance methods supported by the given specification version
198
+ */
199
+ getInterface(specVersion) {
200
+ if (specVersion.lt("2.0")) {
201
+ // Custom middleware defining specVersion <2.0 does not have access to any MiddlewareUtil API
202
+ return undefined;
203
+ }
204
+
205
+ const baseInterface = {};
206
+ bindFunctions(this, baseInterface, [
207
+ "getPathname", "getMimeInfo"
208
+ ]);
209
+
210
+ if (specVersion.gte("3.0")) {
211
+ // getProject function, returning an interfaced project instance
212
+ baseInterface.getProject = (projectName) => {
213
+ const project = this.getProject(projectName);
214
+ const baseProjectInterface = {};
215
+ bindFunctions(project, baseProjectInterface, [
216
+ "getType", "getName", "getVersion", "getNamespace",
217
+ "getRootReader", "getReader", "getCustomConfiguration", "isFrameworkProject"
218
+ ]);
219
+ return baseProjectInterface;
220
+ };
221
+ // getDependencies function, returning an array of project names
222
+ baseInterface.getDependencies = (projectName) => {
223
+ return this.getDependencies(projectName);
224
+ };
225
+
226
+ baseInterface.resourceFactory = Object.create(null);
227
+ [
228
+ // Once new functions get added, extract this array into a variable
229
+ // and enhance based on spec version once new functions get added
230
+ "createResource", "createReaderCollection", "createReaderCollectionPrioritized",
231
+ "createFilterReader", "createLinkReader", "createFlatReader",
232
+ ].forEach((factoryFunction) => {
233
+ baseInterface.resourceFactory[factoryFunction] = this.resourceFactory[factoryFunction];
234
+ });
235
+ }
236
+ return baseInterface;
237
+ }
238
+ }
239
+
240
+ function bindFunctions(sourceObject, targetObject, funcNames) {
241
+ funcNames.forEach((funcName) => {
242
+ targetObject[funcName] = sourceObject[funcName].bind(sourceObject);
243
+ });
103
244
  }
104
245
 
105
246
  export default MiddlewareUtil;
@@ -76,7 +76,7 @@ function createMiddleware({resources}) {
76
76
  ]).then(function(results) {
77
77
  const libraryResources = results[0];
78
78
  const testPageResources = results[1];
79
- const libs = {};
79
+ const libs = Object.create(null);
80
80
 
81
81
  libraryResources.forEach(function(resource) {
82
82
  const relPath = resource.getPath().substr(11); // cut off leading "/resources/"
@@ -33,12 +33,6 @@ function createMiddleware({resources, middlewareUtil}) {
33
33
  next();
34
34
  return;
35
35
  }
36
- if (log.isLevelEnabled("verbose")) {
37
- const {
38
- default: treeify
39
- } = await import("treeify");
40
- log.verbose("\n" + treeify.asTree(resource.getPathTree()));
41
- }
42
36
 
43
37
  const resourcePath = resource.getPath();
44
38
  if (rProperties.test(resourcePath)) {
@@ -48,7 +42,7 @@ function createMiddleware({resources, middlewareUtil}) {
48
42
  let propertiesFileSourceEncoding = project?.getPropertiesFileSourceEncoding();
49
43
 
50
44
  if (!propertiesFileSourceEncoding) {
51
- if (project && ["0.1", "1.0", "1.1"].includes(project.getSpecVersion())) {
45
+ if (project && project.getSpecVersion().lte("1.1")) {
52
46
  // default encoding to "ISO-8859-1" for old specVersions
53
47
  propertiesFileSourceEncoding = "ISO-8859-1";
54
48
  } else {
@@ -43,9 +43,9 @@ function createMiddleware({resources, middlewareUtil}) {
43
43
  const builder = new ThemeBuilder({
44
44
  fs: fsInterface(resources.all)
45
45
  });
46
- const buildOptions = {};
46
+ const buildOptions = Object.create(null);
47
47
 
48
- const currentRequests = {};
48
+ const currentRequests = Object.create(null);
49
49
 
50
50
  async function buildTheme(pathname) {
51
51
  const filename = basename(pathname);
@@ -8,7 +8,7 @@ import logger from "@ui5/logger";
8
8
  const log = logger.getLogger("server:middleware:testRunner");
9
9
 
10
10
  const testRunnerResourceRegEx = /\/test-resources\/sap\/ui\/qunit\/(testrunner\.(html|css)|TestRunner.js)$/;
11
- const resourceCache = {};
11
+ const resourceCache = Object.create(null);
12
12
 
13
13
  function serveResource(res, resourcePath, resourceContent) {
14
14
  const type = mime.lookup(resourcePath) || "application/octet-stream";
package/lib/server.js CHANGED
@@ -142,7 +142,7 @@ export async function serve(graph, {
142
142
  // Ignore root project
143
143
  return;
144
144
  }
145
- readers.push(await dep.getReader({style: "runtime"}));
145
+ readers.push(dep.getReader({style: "runtime"}));
146
146
  });
147
147
 
148
148
  const dependencies = createReaderCollection({
@@ -150,7 +150,7 @@ export async function serve(graph, {
150
150
  readers
151
151
  });
152
152
 
153
- const rootReader = await rootProject.getReader({style: "runtime"});
153
+ const rootReader = rootProject.getReader({style: "runtime"});
154
154
 
155
155
  // TODO change to ReaderCollection once duplicates are sorted out
156
156
  const combo = new ReaderCollectionPrioritized({
@@ -165,6 +165,7 @@ export async function serve(graph, {
165
165
 
166
166
  const middlewareManager = new MiddlewareManager({
167
167
  graph,
168
+ rootProject,
168
169
  resources,
169
170
  options: {
170
171
  sendSAPTargetCSP,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ui5/server",
3
- "version": "3.0.0-beta.1",
3
+ "version": "3.0.0-beta.3",
4
4
  "description": "UI5 Tooling - Server",
5
5
  "author": {
6
6
  "name": "SAP SE",
@@ -25,7 +25,7 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "engines": {
28
- "node": ">= 16.13.2",
28
+ "node": "^16.18.0 || >=18.0.0",
29
29
  "npm": ">= 8"
30
30
  },
31
31
  "scripts": {
@@ -115,9 +115,9 @@
115
115
  "url": "git@github.com:SAP/ui5-server.git"
116
116
  },
117
117
  "dependencies": {
118
- "@ui5/builder": "^3.0.0-beta.1",
119
- "@ui5/fs": "^3.0.0-beta.2",
120
- "@ui5/logger": "^3.0.1-beta.0",
118
+ "@ui5/builder": "^3.0.0-beta.3",
119
+ "@ui5/fs": "^3.0.0-beta.3",
120
+ "@ui5/logger": "^3.0.1-beta.1",
121
121
  "body-parser": "^1.20.1",
122
122
  "compression": "^1.7.4",
123
123
  "connect-openui5": "^0.10.2",
@@ -127,35 +127,34 @@
127
127
  "etag": "^1.8.1",
128
128
  "express": "^4.18.2",
129
129
  "fresh": "^0.5.2",
130
- "graceful-fs": "^4.2.9",
130
+ "graceful-fs": "^4.2.10",
131
131
  "make-dir": "^3.1.0",
132
- "mime-types": "^2.1.34",
132
+ "mime-types": "^2.1.35",
133
133
  "parseurl": "^1.3.3",
134
- "portscanner": "^2.1.1",
134
+ "portscanner": "^2.2.0",
135
135
  "replacestream": "^4.0.3",
136
- "router": "^1.3.6",
136
+ "router": "^1.3.7",
137
137
  "spdy": "^4.0.2",
138
- "treeify": "^1.0.1",
139
138
  "yesno": "^0.3.1"
140
139
  },
141
140
  "devDependencies": {
142
141
  "@istanbuljs/esm-loader-hook": "^0.2.0",
143
- "@ui5/project": "^3.0.0-alpha.10",
144
- "ava": "^5.0.1",
142
+ "@ui5/project": "^3.0.0-beta.3",
143
+ "ava": "^5.1.0",
145
144
  "chokidar-cli": "^3.0.0",
146
145
  "cross-env": "^7.0.3",
147
146
  "depcheck": "^1.4.3",
148
- "docdash": "^1.2.0",
149
- "eslint": "^8.26.0",
147
+ "docdash": "^2.0.0",
148
+ "eslint": "^8.28.0",
150
149
  "eslint-config-google": "^0.14.0",
151
- "eslint-plugin-ava": "^13.0.2",
152
- "eslint-plugin-jsdoc": "^39.6.2",
153
- "esmock": "^2.0.7",
154
- "jsdoc": "^3.6.7",
150
+ "eslint-plugin-ava": "^13.2.0",
151
+ "eslint-plugin-jsdoc": "^39.6.4",
152
+ "esmock": "^2.0.9",
153
+ "jsdoc": "^3.6.11",
155
154
  "nyc": "^15.1.0",
156
155
  "open-cli": "^7.1.0",
157
156
  "rimraf": "^3.0.2",
158
- "sinon": "^14.0.1",
157
+ "sinon": "^14.0.2",
159
158
  "supertest": "^6.3.1",
160
159
  "tap-nyan": "^1.1.0",
161
160
  "tap-xunit": "^2.4.1"