Skip to content

Commit b612983

Browse files
authored
[ui5-server][BREAKING] Require Project Graph (#479)
Adapt to new Project Graph API (see SAP/ui5-project#457) BREAKING CHANGE: * Server now requires a Project Graph instance instead. * Standard middleware now rely on Project instances being available on Resources (see SAP/ui5-fs#381) * MiddlewareRepository#addMiddleware has been removed. Custom middleware need to be added to the project graph instead
1 parent 09bbc26 commit b612983

File tree

259 files changed

+418
-2153
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

259 files changed

+418
-2153
lines changed

packages/server/lib/middleware/MiddlewareManager.js

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty);
1717
* @memberof module:@ui5/server.middleware
1818
*/
1919
class MiddlewareManager {
20-
constructor({tree, resources, options = {
20+
constructor({graph, resources, options = {
2121
sendSAPTargetCSP: false,
2222
serveCSPReports: false
2323
}}) {
24-
if (!tree || !resources || !resources.all || !resources.rootProject || !resources.dependencies) {
24+
if (!graph || !resources || !resources.all || !resources.rootProject || !resources.dependencies) {
2525
throw new Error("[MiddlewareManager]: One or more mandatory parameters not provided");
2626
}
27-
this.tree = tree;
27+
this.graph = graph;
2828
this.resources = resources;
2929
this.options = options;
3030

@@ -44,15 +44,19 @@ class MiddlewareManager {
4444
}
4545

4646
async addMiddleware(configuredMiddlewareName, {
47-
wrapperCallback, mountPath = "/",
47+
customMiddleware, wrapperCallback, mountPath = "/",
4848
beforeMiddleware, afterMiddleware
4949
} = {}) {
50-
const middlewareInfo = middlewareRepository.getMiddleware(configuredMiddlewareName);
5150
let middlewareCallback;
52-
if (wrapperCallback) {
53-
middlewareCallback = wrapperCallback(middlewareInfo);
51+
if (customMiddleware) {
52+
middlewareCallback = customMiddleware;
5453
} 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+
}
5660
}
5761

5862
let middlewareName = configuredMiddlewareName;
@@ -188,7 +192,7 @@ class MiddlewareManager {
188192
return versionInfoModule({
189193
resources,
190194
middlewareUtil,
191-
tree: this.tree
195+
graph: this.graph
192196
});
193197
};
194198
}
@@ -211,47 +215,46 @@ class MiddlewareManager {
211215
}
212216

213217
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) {
217221
return; // No custom middleware defined
218222
}
219223

220224
for (let i = 0; i < projectCustomMiddleware.length; i++) {
221225
const middlewareDef = projectCustomMiddleware[i];
222226
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()} ` +
224228
`at index ${i}`);
225229
}
226230
if (middlewareDef.beforeMiddleware && middlewareDef.afterMiddleware) {
227231
throw new Error(
228-
`Custom middleware definition ${middlewareDef.name} of project ${project.metadata.name} ` +
232+
`Custom middleware definition ${middlewareDef.name} of project ${project.getName()} ` +
229233
`defines both "beforeMiddleware" and "afterMiddleware" parameters. Only one must be defined.`);
230234
}
231235
if (!middlewareDef.beforeMiddleware && !middlewareDef.afterMiddleware) {
232236
throw new Error(
233-
`Custom middleware definition ${middlewareDef.name} of project ${project.metadata.name} ` +
237+
`Custom middleware definition ${middlewareDef.name} of project ${project.getName()} ` +
234238
`defines neither a "beforeMiddleware" nor an "afterMiddleware" parameter. One must be defined.`);
235239
}
236-
237240
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
254246
};
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);
255258
},
256259
mountPath: middlewareDef.mountPath,
257260
beforeMiddleware: middlewareDef.beforeMiddleware,

packages/server/lib/middleware/middlewareRepository.js

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,14 @@ function getMiddleware(middlewareName) {
2121
try {
2222
const middleware = require(middlewareInfo.path);
2323
return {
24-
middleware,
25-
specVersion: middlewareInfo.specVersion
24+
middleware
2625
};
2726
} catch (err) {
2827
throw new Error(
2928
`middlewareRepository: Failed to require middleware module for ${middlewareName}: ${err.message}`);
3029
}
3130
}
3231

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-
4332
module.exports = {
44-
getMiddleware: getMiddleware,
45-
addMiddleware: addMiddleware
33+
getMiddleware: getMiddleware
4634
};

packages/server/lib/middleware/serveIndex.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,8 @@ function createResourceInfo(resource) {
5454
lastModified: new Date(stat.mtime).toLocaleString(),
5555
size: formatSize(stat.size),
5656
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>"
6059
};
6160
}
6261

packages/server/lib/middleware/serveResources.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,11 @@ function createMiddleware({resources, middlewareUtil}) {
4141
if (rProperties.test(resourcePath)) {
4242
// Special handling for *.properties files escape non ascii characters.
4343
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();
4746

4847
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())) {
5049
// default encoding to "ISO-8859-1" for old specVersions
5150
propertiesFileSourceEncoding = "ISO-8859-1";
5251
} else {
@@ -84,9 +83,9 @@ function createMiddleware({resources, middlewareUtil}) {
8483
// Also, only process .library, *.js and *.json files. Just like it's done in Application-
8584
// and LibraryBuilder
8685
if ((!charset || charset === "UTF-8") && rReplaceVersion.test(resourcePath)) {
87-
if (resource._project) {
86+
if (resource.getProject()) {
8887
stream.setEncoding("utf8");
89-
stream = stream.pipe(replaceStream("${version}", resource._project.version));
88+
stream = stream.pipe(replaceStream("${version}", resource.getProject().getVersion()));
9089
} else {
9190
log.verbose("Project missing from resource %s", pathname);
9291
}

packages/server/lib/middleware/versionInfo.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,21 @@ const MANIFEST_JSON = "manifest.json";
99
* @module @ui5/server/middleware/versionInfo
1010
* @param {object} parameters Parameters
1111
* @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
1313
* @returns {Function} Returns a server middleware closure.
1414
*/
15-
function createMiddleware({resources, tree: project}) {
15+
function createMiddleware({resources, graph}) {
1616
return async function versionInfo(req, res, next) {
1717
try {
1818
const dependencies = resources.dependencies;
1919
const dotLibResources = await dependencies.byGlob("/resources/**/.library");
2020

2121
dotLibResources.sort((a, b) => {
22-
return a._project.metadata.name.localeCompare(b._project.metadata.name);
22+
return a.getProject().getName().localeCompare(b.getProject().getName());
2323
});
2424

2525
const libraryInfosPromises = dotLibResources.map(async (dotLibResource) => {
26-
const namespace = dotLibResource._project.metadata.namespace;
26+
const namespace = dotLibResource.getProject().getNamespace();
2727
const manifestResources = await dependencies.byGlob(`/resources/${namespace}/**/${MANIFEST_JSON}`);
2828
let libraryManifest = manifestResources.find((manifestResource) => {
2929
return manifestResource.getPath() === `/resources/${namespace}/${MANIFEST_JSON}`;
@@ -40,22 +40,25 @@ function createMiddleware({resources, tree: project}) {
4040
resources: libResources,
4141
options: {
4242
omitMinVersions: true
43+
},
44+
getProjectVersion: (projectName) => {
45+
return graph.getProject(projectName)?.getVersion();
4346
}
4447
});
4548
}
4649
return {
4750
libraryManifest,
4851
embeddedManifests,
49-
name: dotLibResource._project.metadata.name,
50-
version: dotLibResource._project.version
52+
name: dotLibResource.getProject().getName(),
53+
version: dotLibResource.getProject().getVersion()
5154
};
5255
});
56+
const rootProject = graph.getRoot();
5357
const libraryInfos = await Promise.all(libraryInfosPromises);
54-
5558
const [versionInfoResource] = await createVersionInfoProcessor({
5659
options: {
57-
rootProjectName: project.metadata.name,
58-
rootProjectVersion: project.version,
60+
rootProjectName: rootProject.getName(),
61+
rootProjectVersion: rootProject.getVersion(),
5962
libraryInfos
6063
}
6164
});

packages/server/lib/server.js

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ module.exports = {
112112
* Start a server for the given project (sub-)tree.
113113
*
114114
* @public
115-
* @param {object} tree A (sub-)tree
115+
* @param {module:@ui5/project.graph.ProjectGraph} graph Project graph
116116
* @param {object} options Options
117117
* @param {number} options.port Port to listen to
118118
* @param {boolean} [options.changePortIfInUse=false] If true, change the port if it is already in use
@@ -133,27 +133,41 @@ module.exports = {
133133
* <code>h2</code>-flag and a <code>close</code> function,
134134
* which can be used to stop the server.
135135
*/
136-
async serve(tree, {
136+
async serve(graph, {
137137
port: requestedPort, changePortIfInUse = false, h2 = false, key, cert,
138138
acceptRemoteConnections = false, sendSAPTargetCSP = false, simpleIndex = false, serveCSPReports = false
139139
}) {
140-
const projectResourceCollections = resourceFactory.createCollectionsForTree(tree);
140+
const rootProject = graph.getRoot();
141141

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"});
142157

143158
// TODO change to ReaderCollection once duplicates are sorted out
144159
const combo = new ReaderCollectionPrioritized({
145160
name: "server - prioritize workspace over dependencies",
146-
readers: [projectResourceCollections.source, projectResourceCollections.dependencies]
161+
readers: [rootReader, dependencies]
147162
});
148-
149163
const resources = {
150-
rootProject: projectResourceCollections.source,
151-
dependencies: projectResourceCollections.dependencies,
164+
rootProject: rootReader,
165+
dependencies: dependencies,
152166
all: combo
153167
};
154168

155169
const middlewareManager = new MiddlewareManager({
156-
tree,
170+
graph,
157171
resources,
158172
options: {
159173
sendSAPTargetCSP,

packages/server/test/expected/build/application.a/dest-dev/index.html

Lines changed: 0 additions & 9 deletions
This file was deleted.

packages/server/test/expected/build/application.a/dest-dev/test.js

Lines changed: 0 additions & 5 deletions
This file was deleted.

packages/server/test/expected/build/application.a/dest/index.html

Lines changed: 0 additions & 9 deletions
This file was deleted.

packages/server/test/expected/build/application.a/dest/test-dbg.js

Lines changed: 0 additions & 5 deletions
This file was deleted.

0 commit comments

Comments
 (0)