Skip to content

Commit f801aa9

Browse files
committed
Merge Configuration and Specification into one entity
Implement full Application spec
1 parent 820d6c0 commit f801aa9

File tree

12 files changed

+723
-227
lines changed

12 files changed

+723
-227
lines changed

lib/Specification.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/**
2+
* @param {object} parameters Specification parameters
3+
* @param {string} parameters.id Unique ID
4+
* @param {string} parameters.version Version
5+
* @param {string} parameters.modulePath File System path to access resources
6+
* @param {object} parameters.configuration Configuration object to use
7+
*/
8+
module.exports = {
9+
// async create(specParams) {
10+
// if (!specParams.configuration) {
11+
// throw new Error(`Unable to create Specification: No configuration provided`);
12+
// }
13+
// switch (specParams.configuration.kind) {
14+
// case "project":
15+
// return Project.create(specParams);
16+
// case "extension":
17+
// return Extension.create(specParams);
18+
// default:
19+
// throw new Error(
20+
// `Encountered unexpected specification configuration of kind ${specParams.configuration.kind} ` +
21+
// `Supported kinds are 'project' and 'extension'`);
22+
// }
23+
// }
24+
25+
async create(params) {
26+
if (!["project", "extension"].includes(params.configuration.kind)) {
27+
throw new Error(`Unable to create Specification instance: Unknown kind '${params.configuration.kind}'`);
28+
}
29+
30+
switch (params.configuration.type) {
31+
case "application": {
32+
return createAndInitializeSpec("Application", params);
33+
}
34+
case "library": {
35+
return createAndInitializeSpec("Library", params);
36+
}
37+
case "theme-library": {
38+
return createAndInitializeSpec("ThemeLibrary", params);
39+
}
40+
case "module": {
41+
return createAndInitializeSpec("Module", params);
42+
}
43+
case "task": {
44+
return createAndInitializeSpec("Task", params);
45+
}
46+
case "middleware": {
47+
return createAndInitializeSpec("Middleware", params);
48+
}
49+
case "project-shim": {
50+
return createAndInitializeSpec("ProjectShim", params);
51+
}
52+
default:
53+
throw new Error(
54+
`Unable to create Specification instance: Unknown specification type '${params.configuration.type}'`);
55+
}
56+
}
57+
};
58+
59+
function createAndInitializeSpec(moduleName, params) {
60+
const Spec = require(`./specifications/types/${moduleName}`);
61+
const bla = new Spec().init(params);
62+
return bla;
63+
}

lib/graph/Module.js

Lines changed: 129 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ const {promisify} = require("util");
44
const readFile = promisify(fs.readFile);
55
const jsyaml = require("js-yaml");
66
const resourceFactory = require("@ui5/fs").resourceFactory;
7-
const Project = require("../specifications/Project");
8-
const Extension = require("../specifications/Extension");
9-
const Configuration = require("../specifications/Configuration");
7+
const Specification = require("../Specification");
108
const {validate} = require("../validation/validator");
119

1210
const log = require("@ui5/logger").getLogger("graph:Module");
@@ -93,44 +91,66 @@ class Module {
9391
async _getSpecifications() {
9492
const configs = await this._getConfigurations();
9593

96-
let project;
97-
const extensions = [];
98-
configs.forEach((configuration) => {
99-
const kind = configuration.getKind();
100-
101-
switch (kind) {
102-
case "project":
103-
if (project) {
104-
throw new Error(
105-
`Invalid configuration for module ${this.getId()}: Per module there ` +
106-
`must be no more than one configuration of kind 'project'`);
107-
}
108-
log.verbose(`Module ${this.getId()} contains project ${configuration.getName()}`);
109-
project = new Project({
110-
id: this.getId(),
111-
version: this.getVersion(),
112-
modulePath: this.getPath(),
113-
configuration
114-
});
115-
break;
116-
case "extension":
117-
log.verbose(`Module ${this.getId()} contains extension ${configuration.getName()}`);
118-
extensions.push(new Extension({
119-
id: this.getId(),
120-
version: this.getVersion(),
121-
modulePath: this.getPath(),
122-
configuration
123-
}));
124-
break;
125-
default:
126-
throw new Error(
127-
`Encountered unexpected specification configuration of kind ${kind} ` +
128-
`Supported kinds are 'project' and 'extension'`);
129-
}
94+
// let project;
95+
// const extensions = [];
96+
const specs = await Promise.all(configs.map(async (configuration) => {
97+
const spec = await Specification.create({
98+
id: this.getId(),
99+
version: this.getVersion(),
100+
modulePath: this.getPath(),
101+
configuration
102+
});
103+
104+
log.verbose(`Module ${this.getId()} contains ${spec.getKind()} ${spec.getName()}`);
105+
return spec;
106+
107+
// switch (configuration.kind) {
108+
// case "project":
109+
// if (project) {
110+
// throw new Error(
111+
// `Invalid configuration for module ${this.getId()}: Per module there ` +
112+
// `must be no more than one configuration of kind 'project'`);
113+
// }
114+
// log.verbose(`Module ${this.getId()} contains project ${configuration.getName()}`);
115+
// project = await Project.create({
116+
// id: this.getId(),
117+
// version: this.getVersion(),
118+
// modulePath: this.getPath(),
119+
// configuration
120+
// });
121+
// break;
122+
// case "extension":
123+
// log.verbose(`Module ${this.getId()} contains extension ${configuration.getName()}`);
124+
// extensions.push(new Extension({
125+
// id: this.getId(),
126+
// version: this.getVersion(),
127+
// modulePath: this.getPath(),
128+
// configuration
129+
// }));
130+
// break;
131+
// default:
132+
// throw new Error(
133+
// `Encountered unexpected specification configuration of kind ${configuration.kind} ` +
134+
// `Supported kinds are 'project' and 'extension'`);
135+
// }
136+
}));
137+
138+
const projects = specs.filter((spec) => {
139+
return spec.getKind() === "project";
140+
});
141+
142+
const extensions = specs.filter((spec) => {
143+
return spec.getKind() === "extension";
130144
});
131145

146+
if (projects.length > 1) {
147+
throw new Error(
148+
`Found ${projects.length} configurations of kind 'project' for ` +
149+
`module ${this.getId()}. There must be only one project per module.`);
150+
}
151+
132152
return {
133-
project,
153+
project: projects[0],
134154
extensions
135155
};
136156
}
@@ -152,21 +172,21 @@ class Module {
152172
return configurations || [];
153173
}
154174

155-
async _createConfigurationInstance(config) {
175+
async _createConfigurationObject(config) {
156176
this._normalizeConfig(config);
157177
if (config.kind === "project") {
158178
this._applyShims(config);
159179
}
160-
await this._validateConfig(config);
161-
return new Configuration(config);
180+
// await this._validateConfig(config);
181+
return config;
162182
}
163183

164184
async _createConfigurationFromShim() {
165185
const config = this._applyShims();
166186
if (config) {
167187
this._normalizeConfig(config);
168-
await this._validateConfig(config);
169-
return new Configuration(config);
188+
// await this._validateConfig(config);
189+
return config;
170190
}
171191
}
172192

@@ -185,7 +205,7 @@ class Module {
185205
if (this._suppliedConfigs.length) {
186206
log.verbose(`Configuration for module ${this.getId()} has been supplied directly`);
187207
return await Promise.all(this._suppliedConfigs.map(async (config) => {
188-
return this._createConfigurationInstance(config);
208+
return this._createConfigurationObject(config);
189209
}));
190210
}
191211
}
@@ -208,43 +228,45 @@ class Module {
208228
return [];
209229
}
210230

211-
for (let i = configs.length - 1; i >= 0; i--) {
212-
this._normalizeConfig(configs[i]);
213-
}
214-
215-
const projectConfigs = configs.filter((config) => {
216-
return config.kind === "project";
217-
});
218-
219-
const extensionConfigs = configs.filter((config) => {
220-
return config.kind === "extension";
221-
});
222-
223-
// While a project can contain multiple configurations,
224-
// from a dependency tree perspective it is always a single project
225-
// This means it can represent one "project", plus multiple extensions or
226-
// one extension, plus multiple extensions
227-
228-
if (projectConfigs.length > 1) {
229-
throw new Error(
230-
`Found ${projectConfigs.length} configurations of kind 'project' for ` +
231-
`project ${this.getId()}. There is only one project per configuration allowed.`);
232-
} else if (projectConfigs.length === 0 && extensionConfigs.length === 0) {
233-
throw new Error(
234-
`Found ${configs.length} configurations for ` +
235-
`project ${this.getId()}. However, none of them are of kind 'project' or 'extension'.`);
236-
}
237-
238-
const configurations = [];
239-
if (projectConfigs.length) {
240-
configurations.push(await this._createConfigurationInstance(projectConfigs[0]));
241-
}
242-
243-
await Promise.all(extensionConfigs.map(async (config) => {
244-
configurations.push(await this._createConfigurationInstance(config));
231+
// for (let i = configs.length - 1; i >= 0; i--) {
232+
// this._normalizeConfig(configs[i]);
233+
// }
234+
235+
// const projectConfigs = configs.filter((config) => {
236+
// return config.kind === "project";
237+
// });
238+
239+
// const extensionConfigs = configs.filter((config) => {
240+
// return config.kind === "extension";
241+
// });
242+
243+
// // While a project can contain multiple configurations,
244+
// // from a dependency tree perspective it is always a single project
245+
// // This means it can represent one "project", plus multiple extensions or
246+
// // one extension, plus multiple extensions
247+
248+
// if (projectConfigs.length > 1) {
249+
// throw new Error(
250+
// `Found ${projectConfigs.length} configurations of kind 'project' for ` +
251+
// `project ${this.getId()}. There is only one project per configuration allowed.`);
252+
// } else if (projectConfigs.length === 0 && extensionConfigs.length === 0) {
253+
// throw new Error(
254+
// `Found ${configs.length} configurations for ` +
255+
// `project ${this.getId()}. However, none of them are of kind 'project' or 'extension'.`);
256+
// }
257+
258+
// const configurations = [];
259+
// if (projectConfigs.length) {
260+
// configurations.push(await this._createConfigurationObject(projectConfigs[0]));
261+
// }
262+
263+
// await Promise.all(extensionConfigs.map(async (config) => {
264+
// configurations.push(await this._createConfigurationObject(config));
265+
// }));
266+
267+
return await Promise.all(configs.map((config) => {
268+
return this._createConfigurationObject(config);
245269
}));
246-
247-
return configurations;
248270
}
249271

250272
async _readConfigFile() {
@@ -339,33 +361,33 @@ class Module {
339361
return config;
340362
}
341363

342-
async _validateConfig(config) {
343-
const moduleId = this.getId();
344-
if (!moduleId.startsWith("@openui5/") && !moduleId.startsWith("@sapui5/")) {
345-
if (config.specVersion === "0.1" || config.specVersion === "1.0" ||
346-
config.specVersion === "1.1") {
347-
throw new Error(
348-
`Unsupported specification version ${config.specVersion} defined in module ` +
349-
`${this.getId()}. The new Module API can only be used with specification versions >= 2.0. ` +
350-
`For details see https://sap.github.io/ui5-tooling/pages/Configuration/#specification-versions`);
351-
}
352-
if (config.specVersion !== "2.0" &&
353-
config.specVersion !== "2.1" && config.specVersion !== "2.2" &&
354-
config.specVersion !== "2.3") {
355-
throw new Error(
356-
`Unsupported specification version ${config.specVersion} defined in module ` +
357-
`${this.getId()}. Your UI5 CLI installation might be outdated. ` +
358-
`For details see https://sap.github.io/ui5-tooling/pages/Configuration/#specification-versions`);
359-
}
360-
}
361-
362-
await validate({
363-
config,
364-
project: {
365-
id: moduleId
366-
}
367-
});
368-
}
364+
// async _validateConfig(config) {
365+
// const moduleId = this.getId();
366+
// if (!moduleId.startsWith("@openui5/") && !moduleId.startsWith("@sapui5/")) {
367+
// if (config.specVersion === "0.1" || config.specVersion === "1.0" ||
368+
// config.specVersion === "1.1") {
369+
// throw new Error(
370+
// `Unsupported specification version ${config.specVersion} defined in module ` +
371+
// `${this.getId()}. The new Module API can only be used with specification versions >= 2.0. ` +
372+
// `For details see https://sap.github.io/ui5-tooling/pages/Configuration/#specification-versions`);
373+
// }
374+
// if (config.specVersion !== "2.0" &&
375+
// config.specVersion !== "2.1" && config.specVersion !== "2.2" &&
376+
// config.specVersion !== "2.3") {
377+
// throw new Error(
378+
// `Unsupported specification version ${config.specVersion} defined in module ` +
379+
// `${this.getId()}. Your UI5 CLI installation might be outdated. ` +
380+
// `For details see https://sap.github.io/ui5-tooling/pages/Configuration/#specification-versions`);
381+
// }
382+
// }
383+
384+
// await validate({
385+
// config,
386+
// project: {
387+
// id: moduleId
388+
// }
389+
// });
390+
// }
369391

370392
_isConfigValid(project) {
371393
if (!project.type) {

lib/graph/ProjectGraph.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ class ProjectGraph {
275275

276276
/**
277277
* Helper function available in the
278-
* traversalCallback]{@link module:@ui5/project.graph.ProjectGraph~traversalCallback} to access the
278+
* [traversalCallback]{@link module:@ui5/project.graph.ProjectGraph~traversalCallback} to access the
279279
* dependencies of the corresponding project in the current graph.
280280
* <br><br>
281281
* Note that transitive dependencies can't be accessed this way. Projects should rather add a direct
@@ -286,6 +286,8 @@ class ProjectGraph {
286286
* @returns {Array.<module:@ui5/project.specifications.Project>} Direct dependencies of the visited project
287287
*/
288288

289+
290+
// TODO: Use generator functions instead?
289291
/**
290292
* Visit every project in the graph that can be reached by the given entry project exactly once.
291293
* The entry project defaults to the root project.

0 commit comments

Comments
 (0)