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

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,13 @@
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.2...HEAD).
6
+
7
+ <a name="v3.0.0-beta.2"></a>
8
+ ## [v3.0.0-beta.2] - 2022-11-29
9
+ ### Features
10
+ - **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)
11
+
6
12
 
7
13
  <a name="v3.0.0-beta.1"></a>
8
14
  ## [v3.0.0-beta.1] - 2022-11-07
@@ -293,6 +299,7 @@ Only Node.js v10 or higher is supported.
293
299
  <a name="v0.0.1"></a>
294
300
  ## v0.0.1 - 2018-06-06
295
301
 
302
+ [v3.0.0-beta.2]: https://github.com/SAP/ui5-server/compare/v3.0.0-beta.1...v3.0.0-beta.2
296
303
  [v3.0.0-beta.1]: https://github.com/SAP/ui5-server/compare/v3.0.0-alpha.4...v3.0.0-beta.1
297
304
  [v3.0.0-alpha.4]: https://github.com/SAP/ui5-server/compare/v3.0.0-alpha.3...v3.0.0-alpha.4
298
305
  [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,12 @@
1
1
  import parseurl from "parseurl";
2
2
  import mime from "mime-types";
3
+ import {
4
+ createReaderCollectionPrioritized,
5
+ createResource,
6
+ createFilterReader,
7
+ createLinkReader,
8
+ createFlatReader
9
+ } from "@ui5/fs/resourceFactory";
3
10
 
4
11
  /**
5
12
  * Convenience functions for UI5 Server middleware.
@@ -17,33 +24,21 @@ import mime from "mime-types";
17
24
  */
18
25
  class MiddlewareUtil {
19
26
  /**
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
27
  *
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
28
+ * @param {object} parameters
29
+ * @param {@ui5/project/graph/ProjectGraph} parameters.graph Relevant ProjectGraph
30
+ * @param {@ui5/project/specifications/Project} parameters.project Project that is being served
31
+ * @public
25
32
  */
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}`);
33
+ constructor({graph, project}) {
34
+ if (!graph) {
35
+ throw new Error(`Missing parameter "graph"`);
36
+ }
37
+ if (!project) {
38
+ throw new Error(`Missing parameter "project"`);
46
39
  }
40
+ this._graph = graph;
41
+ this._project = project;
47
42
  }
48
43
 
49
44
  /**
@@ -100,6 +95,148 @@ class MiddlewareUtil {
100
95
  contentType: type + (charset ? "; charset=" + charset : "")
101
96
  };
102
97
  }
98
+ /**
99
+ * Specification Version-dependent [Project]{@link @ui5/project/specifications/Project} interface.
100
+ * For details on individual functions, see [Project]{@link @ui5/project/specifications/Project}
101
+ *
102
+ * @public
103
+ * @typedef {object} @ui5/project/build/helpers/MiddlewareUtill~ProjectInterface
104
+ * @property {Function} getType Get the project type
105
+ * @property {Function} getName Get the project name
106
+ * @property {Function} getVersion Get the project version
107
+ * @property {Function} getNamespace Get the project namespace
108
+ * @property {Function} getRootReader Get the project rootReader
109
+ * @property {Function} getReader Get the project reader
110
+ * @property {Function} getCustomConfiguration Get the project Custom Configuration
111
+ * @property {Function} isFrameworkProject Check whether the project is a UI5-Framework project
112
+ */
113
+
114
+ /**
115
+ * Retrieve a single project from the dependency graph
116
+ *
117
+ * </br></br>
118
+ * This method is only available to custom server middleware extensions defining
119
+ * <b>Specification Version 3.0 and above</b>.
120
+ *
121
+ * @param {string} [projectName] Name of the project to retrieve. Defaults to the project currently being built
122
+ * @returns {@ui5/project/build/helpers/MiddlewareUtill~ProjectInterface|undefined}
123
+ * project instance or undefined if the project is unknown to the graph
124
+ * @public
125
+ */
126
+ getProject(projectName) {
127
+ if (projectName) {
128
+ return this._graph.getProject(projectName);
129
+ }
130
+ return this._project;
131
+ }
132
+
133
+ /**
134
+ * Retrieve a list of direct dependencies of a given project from the dependency graph.
135
+ * Note that this list does not include transitive dependencies.
136
+ *
137
+ * </br></br>
138
+ * This method is only available to custom server middleware extensions defining
139
+ * <b>Specification Version 3.0 and above</b>.
140
+ *
141
+ * @param {string} [projectName] Name of the project to retrieve. Defaults to the project currently being built
142
+ * @returns {string[]} Names of all direct dependencies
143
+ * @throws {Error} If the requested project is unknown to the graph
144
+ * @public
145
+ */
146
+ getDependencies(projectName) {
147
+ return this._graph.getDependencies(projectName || this._project.getName());
148
+ }
149
+
150
+ /**
151
+ * Specification Version-dependent set of [@ui5/fs/resourceFactory]{@link @ui5/fs/resourceFactory}
152
+ * functions provided to middleware.
153
+ * For details on individual functions, see [@ui5/fs/resourceFactory]{@link @ui5/fs/resourceFactory}
154
+ *
155
+ * @public
156
+ * @typedef {object} @ui5/project/build/helpers/MiddlewareUtill~resourceFactory
157
+ * @property {Function} createResource Creates a [Resource]{@link @ui5/fs/Resource}.
158
+ * Accepts the same parameters as the [Resource]{@link @ui5/fs/Resource} constructor.
159
+ * @property {Function} createReaderCollectionPrioritized Creates a prioritized reader collection:
160
+ * [ReaderCollectionPrioritized]{@link @ui5/fs/ReaderCollectionPrioritized}
161
+ * @property {Function} createFilterReader
162
+ * Create a [Filter-Reader]{@link @ui5/fs/readers/Filter} with the given reader.
163
+ * @property {Function} createLinkReader
164
+ * Create a [Link-Reader]{@link @ui5/fs/readers/Filter} with the given reader.
165
+ * @property {Function} createFlatReader Create a [Link-Reader]{@link @ui5/fs/readers/Link}
166
+ * where all requests are prefixed with <code>/resources/<namespace></code>.
167
+ */
168
+
169
+ /**
170
+ * Provides limited access to [@ui5/fs/resourceFactory]{@link @ui5/fs/resourceFactory} functions
171
+ *
172
+ * </br></br>
173
+ * This attribute is only available to custom server middleware extensions defining
174
+ * <b>Specification Version 3.0 and above</b>.
175
+ *
176
+ * @type {@ui5/project/build/helpers/MiddlewareUtill~resourceFactory}
177
+ * @public
178
+ */
179
+ resourceFactory = {
180
+ createResource,
181
+ createReaderCollectionPrioritized,
182
+ createFilterReader,
183
+ createLinkReader,
184
+ createFlatReader,
185
+ };
186
+
187
+ /**
188
+ * Get an interface to an instance of this class that only provides those functions
189
+ * that are supported by the given custom middleware extension specification version.
190
+ *
191
+ * @param {@ui5/project/specifications/SpecificationVersion} specVersion
192
+ * SpecVersionComparator instance of the custom server middleware
193
+ * @returns {object} An object with bound instance methods supported by the given specification version
194
+ */
195
+ getInterface(specVersion) {
196
+ if (specVersion.lt("2.0")) {
197
+ // Custom middleware defining specVersion <2.0 does not have access to any MiddlewareUtil API
198
+ return undefined;
199
+ }
200
+
201
+ const baseInterface = {};
202
+ bindFunctions(this, baseInterface, [
203
+ "getPathname", "getMimeInfo"
204
+ ]);
205
+
206
+ if (specVersion.gte("3.0")) {
207
+ // getProject function, returning an interfaced project instance
208
+ baseInterface.getProject = (projectName) => {
209
+ const project = this.getProject(projectName);
210
+ const baseProjectInterface = {};
211
+ bindFunctions(project, baseProjectInterface, [
212
+ "getType", "getName", "getVersion", "getNamespace",
213
+ "getRootReader", "getReader", "getCustomConfiguration", "isFrameworkProject"
214
+ ]);
215
+ return baseProjectInterface;
216
+ };
217
+ // getDependencies function, returning an array of project names
218
+ baseInterface.getDependencies = (projectName) => {
219
+ return this.getDependencies(projectName);
220
+ };
221
+
222
+ baseInterface.resourceFactory = Object.create(null);
223
+ [
224
+ // Once new functions get added, extract this array into a variable
225
+ // and enhance based on spec version once new functions get added
226
+ "createResource", "createReaderCollectionPrioritized",
227
+ "createFilterReader", "createLinkReader", "createFlatReader",
228
+ ].forEach((factoryFunction) => {
229
+ baseInterface.resourceFactory[factoryFunction] = this.resourceFactory[factoryFunction];
230
+ });
231
+ }
232
+ return baseInterface;
233
+ }
234
+ }
235
+
236
+ function bindFunctions(sourceObject, targetObject, funcNames) {
237
+ funcNames.forEach((funcName) => {
238
+ targetObject[funcName] = sourceObject[funcName].bind(sourceObject);
239
+ });
103
240
  }
104
241
 
105
242
  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.2",
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.2",
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"