@ui5/server 2.4.0 → 3.0.0-alpha.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,33 @@
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/v2.4.0...HEAD).
5
+ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-server/compare/v3.0.0-alpha.2...HEAD).
6
+
7
+ <a name="v3.0.0-alpha.2"></a>
8
+ ## [v3.0.0-alpha.2] - 2022-06-14
9
+ ### Breaking Changes
10
+ - Require Project Graph ([#479](https://github.com/SAP/ui5-server/issues/479)) [`d62f85a`](https://github.com/SAP/ui5-server/commit/d62f85a193115a587dbf58225e8130318a475023)
11
+
12
+ ### BREAKING CHANGE
13
+
14
+ * Server now requires a Project Graph instance instead.
15
+ * Standard middleware now rely on Project instances being available on Resources (see https://github.com/SAP/ui5-fs/pull/381)
16
+ * MiddlewareRepository#addMiddleware has been removed. Custom middleware need to be added to the project graph instead
17
+
18
+
19
+ <a name="v3.0.0-alpha.1"></a>
20
+ ## [v3.0.0-alpha.1] - 2022-01-25
21
+ ### Breaking Changes
22
+ - Require Node.js >= 16.13.2 / npm >= 8 [`63d216a`](https://github.com/SAP/ui5-server/commit/63d216a3ba34e8e50acc6621d43a78c3a0804d67)
23
+
24
+ ### BREAKING CHANGE
25
+
26
+ Support for older Node.js and npm releases has been dropped.
27
+ Only Node.js v16.13.2 and npm v8 or higher are supported.
28
+
29
+
30
+ <a name="v3.0.0-alpha.0"></a>
31
+ ## [v3.0.0-alpha.0] - 2021-12-14
6
32
 
7
33
  <a name="v2.4.0"></a>
8
34
  ## [v2.4.0] - 2021-10-19
@@ -246,6 +272,9 @@ Only Node.js v10 or higher is supported.
246
272
  <a name="v0.0.1"></a>
247
273
  ## v0.0.1 - 2018-06-06
248
274
 
275
+ [v3.0.0-alpha.2]: https://github.com/SAP/ui5-server/compare/v3.0.0-alpha.1...v3.0.0-alpha.2
276
+ [v3.0.0-alpha.1]: https://github.com/SAP/ui5-server/compare/v3.0.0-alpha.0...v3.0.0-alpha.1
277
+ [v3.0.0-alpha.0]: https://github.com/SAP/ui5-server/compare/v2.4.0...v3.0.0-alpha.0
249
278
  [v2.4.0]: https://github.com/SAP/ui5-server/compare/v2.3.1...v2.4.0
250
279
  [v2.3.1]: https://github.com/SAP/ui5-server/compare/v2.3.0...v2.3.1
251
280
  [v2.3.0]: https://github.com/SAP/ui5-server/compare/v2.2.10...v2.3.0
package/jsdoc.json CHANGED
@@ -11,7 +11,6 @@
11
11
  "./jsdoc-plugin"
12
12
  ],
13
13
  "opts": {
14
- "template": "node_modules/docdash/",
15
14
  "encoding": "utf8",
16
15
  "destination": "jsdocs/",
17
16
  "recurse": true,
@@ -17,14 +17,14 @@ const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty);
17
17
  * @memberof module:@ui5/server.middleware
18
18
  */
19
19
  class MiddlewareManager {
20
- constructor({tree, resources, options = {
20
+ constructor({graph, resources, options = {
21
21
  sendSAPTargetCSP: false,
22
22
  serveCSPReports: false
23
23
  }}) {
24
- if (!tree || !resources || !resources.all || !resources.rootProject || !resources.dependencies) {
24
+ if (!graph || !resources || !resources.all || !resources.rootProject || !resources.dependencies) {
25
25
  throw new Error("[MiddlewareManager]: One or more mandatory parameters not provided");
26
26
  }
27
- this.tree = tree;
27
+ this.graph = graph;
28
28
  this.resources = resources;
29
29
  this.options = options;
30
30
 
@@ -44,15 +44,19 @@ class MiddlewareManager {
44
44
  }
45
45
 
46
46
  async addMiddleware(configuredMiddlewareName, {
47
- wrapperCallback, mountPath = "/",
47
+ customMiddleware, wrapperCallback, mountPath = "/",
48
48
  beforeMiddleware, afterMiddleware
49
49
  } = {}) {
50
- const middlewareInfo = middlewareRepository.getMiddleware(configuredMiddlewareName);
51
50
  let middlewareCallback;
52
- if (wrapperCallback) {
53
- middlewareCallback = wrapperCallback(middlewareInfo);
51
+ if (customMiddleware) {
52
+ middlewareCallback = customMiddleware;
54
53
  } else {
55
- middlewareCallback = middlewareInfo.middleware;
54
+ const middlewareInfo = middlewareRepository.getMiddleware(configuredMiddlewareName);
55
+ if (wrapperCallback) {
56
+ middlewareCallback = wrapperCallback(middlewareInfo);
57
+ } else {
58
+ middlewareCallback = middlewareInfo.middleware;
59
+ }
56
60
  }
57
61
 
58
62
  let middlewareName = configuredMiddlewareName;
@@ -188,7 +192,7 @@ class MiddlewareManager {
188
192
  return versionInfoModule({
189
193
  resources,
190
194
  middlewareUtil,
191
- tree: this.tree
195
+ graph: this.graph
192
196
  });
193
197
  };
194
198
  }
@@ -211,47 +215,46 @@ class MiddlewareManager {
211
215
  }
212
216
 
213
217
  async addCustomMiddleware() {
214
- const project = this.tree;
215
- const projectCustomMiddleware = project.server && project.server.customMiddleware;
216
- if (!projectCustomMiddleware || projectCustomMiddleware.length === 0) {
218
+ const project = this.graph.getRoot();
219
+ const projectCustomMiddleware = project.getCustomMiddleware();
220
+ if (!projectCustomMiddleware.length === 0) {
217
221
  return; // No custom middleware defined
218
222
  }
219
223
 
220
224
  for (let i = 0; i < projectCustomMiddleware.length; i++) {
221
225
  const middlewareDef = projectCustomMiddleware[i];
222
226
  if (!middlewareDef.name) {
223
- throw new Error(`Missing name for custom middleware definition of project ${project.metadata.name} ` +
227
+ throw new Error(`Missing name for custom middleware definition of project ${project.getName()} ` +
224
228
  `at index ${i}`);
225
229
  }
226
230
  if (middlewareDef.beforeMiddleware && middlewareDef.afterMiddleware) {
227
231
  throw new Error(
228
- `Custom middleware definition ${middlewareDef.name} of project ${project.metadata.name} ` +
232
+ `Custom middleware definition ${middlewareDef.name} of project ${project.getName()} ` +
229
233
  `defines both "beforeMiddleware" and "afterMiddleware" parameters. Only one must be defined.`);
230
234
  }
231
235
  if (!middlewareDef.beforeMiddleware && !middlewareDef.afterMiddleware) {
232
236
  throw new Error(
233
- `Custom middleware definition ${middlewareDef.name} of project ${project.metadata.name} ` +
237
+ `Custom middleware definition ${middlewareDef.name} of project ${project.getName()} ` +
234
238
  `defines neither a "beforeMiddleware" nor an "afterMiddleware" parameter. One must be defined.`);
235
239
  }
236
-
237
240
  await this.addMiddleware(middlewareDef.name, {
238
- wrapperCallback: ({middleware: middleware, specVersion}) => {
239
- return ({resources, middlewareUtil}) => {
240
- const options = {
241
- configuration: middlewareDef.configuration
242
- };
243
- const params = {resources, options};
244
- if (
245
- specVersion === "2.0" || specVersion === "2.1" ||
246
- specVersion === "2.2" || specVersion === "2.3" ||
247
- specVersion === "2.4" || specVersion === "2.5" ||
248
- specVersion === "2.6"
249
- ) {
250
- // Supply interface to MiddlewareUtil instance starting with specVersion 2.0
251
- params.middlewareUtil = middlewareUtil.getInterface(specVersion);
252
- }
253
- return middleware(params);
241
+ customMiddleware: ({resources, middlewareUtil}) => {
242
+ const customMiddleware = this.graph.getExtension(middlewareDef.name);
243
+ const specVersion = customMiddleware.getSpecVersion();
244
+ const options = {
245
+ configuration: middlewareDef.configuration
254
246
  };
247
+ const params = {resources, options};
248
+ if (
249
+ specVersion === "2.0" || specVersion === "2.1" ||
250
+ specVersion === "2.2" || specVersion === "2.3" ||
251
+ specVersion === "2.4" || specVersion === "2.5" ||
252
+ specVersion === "2.6"
253
+ ) {
254
+ // Supply interface to MiddlewareUtil instance starting with specVersion 2.0
255
+ params.middlewareUtil = middlewareUtil.getInterface(specVersion);
256
+ }
257
+ return customMiddleware.getMiddleware()(params);
255
258
  },
256
259
  mountPath: middlewareDef.mountPath,
257
260
  beforeMiddleware: middlewareDef.beforeMiddleware,
@@ -21,8 +21,7 @@ function getMiddleware(middlewareName) {
21
21
  try {
22
22
  const middleware = require(middlewareInfo.path);
23
23
  return {
24
- middleware,
25
- specVersion: middlewareInfo.specVersion
24
+ middleware
26
25
  };
27
26
  } catch (err) {
28
27
  throw new Error(
@@ -30,17 +29,6 @@ function getMiddleware(middlewareName) {
30
29
  }
31
30
  }
32
31
 
33
- function addMiddleware({name, specVersion, middlewarePath}) {
34
- if (middlewareInfos[name]) {
35
- throw new Error(`middlewareRepository: A middleware with the name ${name} has already been registered`);
36
- }
37
- middlewareInfos[name] = {
38
- path: middlewarePath,
39
- specVersion
40
- };
41
- }
42
-
43
32
  module.exports = {
44
- getMiddleware: getMiddleware,
45
- addMiddleware: addMiddleware
33
+ getMiddleware: getMiddleware
46
34
  };
@@ -54,9 +54,8 @@ function createResourceInfo(resource) {
54
54
  lastModified: new Date(stat.mtime).toLocaleString(),
55
55
  size: formatSize(stat.size),
56
56
  sizeInBytes: stat.size,
57
- // TODO: project as public API of FS?
58
- project: resource._project ? resource._project.id : "<unknown>",
59
- projectPath: resource._project ? resource._project.path : "<unknown>"
57
+ project: resource.getProject()?.getName() || "<unknown>",
58
+ projectPath: resource.getProject()?.getPath() || "<unknown>"
60
59
  };
61
60
  }
62
61
 
@@ -41,12 +41,11 @@ function createMiddleware({resources, middlewareUtil}) {
41
41
  if (rProperties.test(resourcePath)) {
42
42
  // Special handling for *.properties files escape non ascii characters.
43
43
  const nonAsciiEscaper = require("@ui5/builder").processors.nonAsciiEscaper;
44
- const project = resource._project; // _project might not be defined
45
- let propertiesFileSourceEncoding = project && project.resources &&
46
- project.resources.configuration && project.resources.configuration.propertiesFileSourceEncoding;
44
+ const project = resource.getProject();
45
+ let propertiesFileSourceEncoding = project?.getPropertiesFileSourceEncoding();
47
46
 
48
47
  if (!propertiesFileSourceEncoding) {
49
- if (project && ["0.1", "1.0", "1.1"].includes(project.specVersion)) {
48
+ if (project && ["0.1", "1.0", "1.1"].includes(project.getSpecVersion())) {
50
49
  // default encoding to "ISO-8859-1" for old specVersions
51
50
  propertiesFileSourceEncoding = "ISO-8859-1";
52
51
  } else {
@@ -84,9 +83,9 @@ function createMiddleware({resources, middlewareUtil}) {
84
83
  // Also, only process .library, *.js and *.json files. Just like it's done in Application-
85
84
  // and LibraryBuilder
86
85
  if ((!charset || charset === "UTF-8") && rReplaceVersion.test(resourcePath)) {
87
- if (resource._project) {
86
+ if (resource.getProject()) {
88
87
  stream.setEncoding("utf8");
89
- stream = stream.pipe(replaceStream("${version}", resource._project.version));
88
+ stream = stream.pipe(replaceStream("${version}", resource.getProject().getVersion()));
90
89
  } else {
91
90
  log.verbose("Project missing from resource %s", pathname);
92
91
  }
@@ -9,21 +9,21 @@ const MANIFEST_JSON = "manifest.json";
9
9
  * @module @ui5/server/middleware/versionInfo
10
10
  * @param {object} parameters Parameters
11
11
  * @param {module:@ui5/server.middleware.MiddlewareManager.middlewareResources} parameters.resources Parameters
12
- * @param {object} parameters.tree Project tree
12
+ * @param {module:@ui5/project.graph.ProjectGraph} parameters.graph Project graph
13
13
  * @returns {Function} Returns a server middleware closure.
14
14
  */
15
- function createMiddleware({resources, tree: project}) {
15
+ function createMiddleware({resources, graph}) {
16
16
  return async function versionInfo(req, res, next) {
17
17
  try {
18
18
  const dependencies = resources.dependencies;
19
19
  const dotLibResources = await dependencies.byGlob("/resources/**/.library");
20
20
 
21
21
  dotLibResources.sort((a, b) => {
22
- return a._project.metadata.name.localeCompare(b._project.metadata.name);
22
+ return a.getProject().getName().localeCompare(b.getProject().getName());
23
23
  });
24
24
 
25
25
  const libraryInfosPromises = dotLibResources.map(async (dotLibResource) => {
26
- const namespace = dotLibResource._project.metadata.namespace;
26
+ const namespace = dotLibResource.getProject().getNamespace();
27
27
  const manifestResources = await dependencies.byGlob(`/resources/${namespace}/**/${MANIFEST_JSON}`);
28
28
  let libraryManifest = manifestResources.find((manifestResource) => {
29
29
  return manifestResource.getPath() === `/resources/${namespace}/${MANIFEST_JSON}`;
@@ -40,22 +40,25 @@ function createMiddleware({resources, tree: project}) {
40
40
  resources: libResources,
41
41
  options: {
42
42
  omitMinVersions: true
43
+ },
44
+ getProjectVersion: (projectName) => {
45
+ return graph.getProject(projectName)?.getVersion();
43
46
  }
44
47
  });
45
48
  }
46
49
  return {
47
50
  libraryManifest,
48
51
  embeddedManifests,
49
- name: dotLibResource._project.metadata.name,
50
- version: dotLibResource._project.version
52
+ name: dotLibResource.getProject().getName(),
53
+ version: dotLibResource.getProject().getVersion()
51
54
  };
52
55
  });
56
+ const rootProject = graph.getRoot();
53
57
  const libraryInfos = await Promise.all(libraryInfosPromises);
54
-
55
58
  const [versionInfoResource] = await createVersionInfoProcessor({
56
59
  options: {
57
- rootProjectName: project.metadata.name,
58
- rootProjectVersion: project.version,
60
+ rootProjectName: rootProject.getName(),
61
+ rootProjectVersion: rootProject.getVersion(),
59
62
  libraryInfos
60
63
  }
61
64
  });
package/lib/server.js CHANGED
@@ -112,7 +112,7 @@ module.exports = {
112
112
  * Start a server for the given project (sub-)tree.
113
113
  *
114
114
  * @public
115
- * @param {object} tree A (sub-)tree
115
+ * @param {module:@ui5/project.graph.ProjectGraph} graph Project graph
116
116
  * @param {object} options Options
117
117
  * @param {number} options.port Port to listen to
118
118
  * @param {boolean} [options.changePortIfInUse=false] If true, change the port if it is already in use
@@ -133,27 +133,41 @@ module.exports = {
133
133
  * <code>h2</code>-flag and a <code>close</code> function,
134
134
  * which can be used to stop the server.
135
135
  */
136
- async serve(tree, {
136
+ async serve(graph, {
137
137
  port: requestedPort, changePortIfInUse = false, h2 = false, key, cert,
138
138
  acceptRemoteConnections = false, sendSAPTargetCSP = false, simpleIndex = false, serveCSPReports = false
139
139
  }) {
140
- const projectResourceCollections = resourceFactory.createCollectionsForTree(tree);
140
+ const rootProject = graph.getRoot();
141
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"});
142
157
 
143
158
  // TODO change to ReaderCollection once duplicates are sorted out
144
159
  const combo = new ReaderCollectionPrioritized({
145
160
  name: "server - prioritize workspace over dependencies",
146
- readers: [projectResourceCollections.source, projectResourceCollections.dependencies]
161
+ readers: [rootReader, dependencies]
147
162
  });
148
-
149
163
  const resources = {
150
- rootProject: projectResourceCollections.source,
151
- dependencies: projectResourceCollections.dependencies,
164
+ rootProject: rootReader,
165
+ dependencies: dependencies,
152
166
  all: combo
153
167
  };
154
168
 
155
169
  const middlewareManager = new MiddlewareManager({
156
- tree,
170
+ graph,
157
171
  resources,
158
172
  options: {
159
173
  sendSAPTargetCSP,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ui5/server",
3
- "version": "2.4.0",
3
+ "version": "3.0.0-alpha.2",
4
4
  "description": "UI5 Tooling - Server",
5
5
  "author": {
6
6
  "name": "SAP SE",
@@ -18,8 +18,8 @@
18
18
  ],
19
19
  "main": "index.js",
20
20
  "engines": {
21
- "node": ">= 10",
22
- "npm": ">= 5"
21
+ "node": ">= 16.13.2",
22
+ "npm": ">= 8"
23
23
  },
24
24
  "scripts": {
25
25
  "test": "npm run lint && npm run jsdoc-generate && npm run coverage && npm run depcheck",
@@ -34,16 +34,17 @@
34
34
  "coverage": "nyc npm run unit",
35
35
  "coverage-xunit": "nyc --reporter=text --reporter=text-summary --reporter=cobertura npm run unit-xunit",
36
36
  "jsdoc": "npm run jsdoc-generate && open-cli jsdocs/index.html",
37
- "jsdoc-generate": "node_modules/.bin/jsdoc -c ./jsdoc.json ./lib/ || (echo 'Error during JSDoc generation! Check log.' && exit 1)",
37
+ "jsdoc-generate": "jsdoc -c ./jsdoc.json -t $(node -p 'path.dirname(require.resolve(\"docdash\"))') ./lib/ || (echo 'Error during JSDoc generation! Check log.' && exit 1)",
38
38
  "jsdoc-watch": "npm run jsdoc && chokidar \"./lib/**/*.js\" -c \"npm run jsdoc-generate\"",
39
39
  "preversion": "npm test",
40
- "version": "git-chglog --next-tag v$npm_package_version -o CHANGELOG.md && git add CHANGELOG.md",
40
+ "version": "git-chglog --sort semver --next-tag v$npm_package_version -o CHANGELOG.md && git add CHANGELOG.md",
41
41
  "postversion": "git push --follow-tags",
42
- "release-note": "git-chglog -c .chglog/release-config.yml v$npm_package_version",
42
+ "release-note": "git-chglog --sort semver -c .chglog/release-config.yml v$npm_package_version",
43
43
  "depcheck": "depcheck --ignores docdash,compression,cors"
44
44
  },
45
45
  "files": [
46
46
  "index.js",
47
+ "CHANGELOG.md",
47
48
  "CONTRIBUTING.md",
48
49
  "jsdoc.json",
49
50
  "lib/**",
@@ -104,46 +105,46 @@
104
105
  "url": "git@github.com:SAP/ui5-server.git"
105
106
  },
106
107
  "dependencies": {
107
- "@ui5/builder": "^2.11.1",
108
- "@ui5/fs": "^2.0.6",
109
- "@ui5/logger": "^2.0.1",
110
- "body-parser": "^1.19.0",
108
+ "@ui5/builder": "^3.0.0-alpha.7",
109
+ "@ui5/fs": "^3.0.0-alpha.4",
110
+ "@ui5/logger": "^3.0.1-alpha.1",
111
+ "body-parser": "^1.19.1",
111
112
  "compression": "^1.7.4",
112
113
  "connect-openui5": "^0.10.2",
113
114
  "cors": "^2.8.5",
114
115
  "devcert-sanscache": "^0.4.8",
115
116
  "escape-html": "^1.0.3",
116
117
  "etag": "^1.8.1",
117
- "express": "^4.17.1",
118
+ "express": "^4.17.2",
118
119
  "fresh": "^0.5.2",
119
- "graceful-fs": "^4.2.8",
120
+ "graceful-fs": "^4.2.9",
120
121
  "make-dir": "^3.1.0",
121
- "mime-types": "^2.1.33",
122
+ "mime-types": "^2.1.34",
122
123
  "parseurl": "^1.3.3",
123
124
  "portscanner": "^2.1.1",
124
125
  "replacestream": "^4.0.3",
125
- "router": "^1.3.5",
126
+ "router": "^1.3.6",
126
127
  "spdy": "^4.0.2",
127
128
  "treeify": "^1.0.1",
128
129
  "yesno": "^0.3.1"
129
130
  },
130
131
  "devDependencies": {
131
- "@ui5/project": "^2.5.0",
132
+ "@ui5/project": "^3.0.0-alpha.3",
132
133
  "ava": "^3.15.0",
133
134
  "chokidar-cli": "^3.0.0",
134
135
  "cross-env": "^7.0.3",
135
- "depcheck": "^1.4.2",
136
+ "depcheck": "^1.4.3",
136
137
  "docdash": "^1.2.0",
137
- "eslint": "^7.32.0",
138
+ "eslint": "^8.7.0",
138
139
  "eslint-config-google": "^0.14.0",
139
- "eslint-plugin-jsdoc": "^36.1.1",
140
+ "eslint-plugin-jsdoc": "^37.6.3",
140
141
  "jsdoc": "^3.6.7",
141
142
  "mock-require": "^3.0.3",
142
143
  "nyc": "^15.1.0",
143
144
  "open-cli": "^6.0.1",
144
145
  "rimraf": "^3.0.2",
145
146
  "sinon": "^11.1.2",
146
- "supertest": "^6.1.6",
147
+ "supertest": "^6.2.1",
147
148
  "tap-nyan": "^1.1.0",
148
149
  "tap-xunit": "^2.4.1"
149
150
  }