Skip to content

Commit

Permalink
[FEATURE] Add shim extension
Browse files Browse the repository at this point in the history
  • Loading branch information
RandomByte committed Oct 16, 2018
1 parent 476b785 commit 93c9b39
Show file tree
Hide file tree
Showing 9 changed files with 297 additions and 54 deletions.
114 changes: 111 additions & 3 deletions lib/projectPreprocessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const typeRepository = require("@ui5/builder").types.typeRepository;
class ProjectPreprocessor {
constructor() {
this.processedProjects = {};
this.configShims = {};
this.collections = {};
}

/*
Expand Down Expand Up @@ -64,7 +66,7 @@ class ProjectPreprocessor {
}

await this.loadProjectConfiguration(project);
// this.applyShims(project); // shims not yet implemented
this.applyShims(project);
if (this.isConfigValid(project)) {
await this.applyType(project);
queue.push({
Expand Down Expand Up @@ -292,8 +294,20 @@ class ProjectPreprocessor {
await type.format(project);
}

async applyExtension(project) {
// TOOD
async applyExtension(extension) {
log.verbose(`Applying extension ${extension.id}...`);

if (!extension.metadata || !extension.metadata.name) {
throw new Error(`metadata.name configuration is missing for extension ${extension.id}`);
} // TODO: more checks? Version?

switch (extension.type) {
case "project-shim":
this.handleShim(extension);
break;
default:
throw new Error(`Unknown extension type '${extension.type}' for ${extension.id}`);
}
}

async readConfigFile(configPath) {
Expand All @@ -302,6 +316,100 @@ class ProjectPreprocessor {
filename: path
});
}

handleShim(extension) {
if (extension.configurations) {
const configurations = extension.configurations;
log.verbose(`Project shim ${extension.id} contains ` +
`${Object.keys(configurations)} configuration(s)`);
for (let projectId in configurations) {
if (configurations.hasOwnProperty(projectId)) {
this.normalizeConfig(configurations[projectId]); // TODO: Clone object beforehand?
if (this.configShims[projectId]) {
log.verbose(`Project shim ${extension.id}: A configuration shim for project ${projectId} `+
"has already been applied. Skipping.");
} else if (this.isConfigValid(configurations[projectId])) {
log.verbose(`Project shim ${extension.id}: Adding project configuration for ${projectId}...`);
this.configShims[projectId] = configurations[projectId];
} else {
log.verbose(`Project shim ${extension.id}: Ignoring invalid ` +
`configuration shim for project ${projectId}`);
}
}
}
}

if (extension.dependencies) {
// For the time being, shimmed dependencies only apply to shimmed project configurations
const dependencies = extension.dependencies;
for (let projectId in dependencies) {
if (dependencies.hasOwnProperty(projectId)) {
if (this.configShims[projectId]) {
log.verbose(`Project shim ${extension.id}: Adding dependencies ` +
`to project shim '${projectId}'...`);
this.configShims[projectId].dependencies = dependencies[projectId];
} else {
log.verbose(`Project shim ${extension.id}: No configuration shim found for ` +
`project ID '${projectId}'. Dependency shims currently only apply ` +
"to projects with configuration shims.");
}
}
}
}

if (extension.collections) {
const collections = extension.collections;
log.verbose(`Project shim ${extension.id} contains ` +
`${Object.keys(collections)} collection(s)`);
for (let projectId in collections) {
if (collections.hasOwnProperty(projectId)) {
if (this.collections[projectId]) {
log.verbose(`Project shim ${extension.id}: A collection with id '${projectId}' `+
"is already known. Skipping.");
} else {
log.verbose(`Project shim ${extension.id}: Adding collection with id '${projectId}'...`);
this.collections[projectId] = collections[projectId];
}
}
}
}
}

applyShims(project) {
// Apply configuration shims
if (this.configShims[project.id]) {
log.verbose(`Applying configuration shim for project ${project.id}...`);
const configShim = JSON.parse(JSON.stringify(this.configShims[project.id]));
Object.assign(project, configShim);
}

// Apply collections
for (let i = project.dependencies.length - 1; i >= 0; i--) {
const depId = project.dependencies[i];
if (this.collections[depId]) {
log.verbose(`Project ${project.id} depends on collection ${depId}. Resolving...`);
// This project contains on a collection
// => replace collection dependency with first collection project.
const collectionDep = project.dependencies[i];
const collection = this.collections[depId];
const projects = [];
for (let projectId in collection) {
if (collection.hasOwnProperty(projectId)) {
// Clone and modify collection "project"
const project = JSON.parse(JSON.stringify(collectionDep));
project.id = projectId;
project.path = path.join(project.path, collection[projectId]);
projects.push(project);
}
}

// Use first collection project to replace the collection dependency
project.dependencies[i] = projects.shift();
// Add any additional collection projects to end of dependency array (already processed)
project.dependencies.push(...projects);
}
}
}
}

/**
Expand Down
11 changes: 11 additions & 0 deletions test/fixtures/legacy.library.a/node_modules/library.f/package.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions test/fixtures/legacy.library.a/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "legacy.library.a",
"version": "1.0.0",
"description": "Simple SAPUI5 based library - legacy library missing ui5.yaml",
"devDependencies": {
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
}
}
11 changes: 11 additions & 0 deletions test/fixtures/legacy.library.a/src/legacy/library/a/.library
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<library xmlns="http://www.sap.com/sap.ui.library.xsd" >

<name>legacy.library.a</name>
<vendor>SAP SE</vendor>
<copyright>${copyright}</copyright>
<version>${version}</version>

<documentation>Legacy Library A</documentation>

</library>
4 changes: 4 additions & 0 deletions test/fixtures/legacy.library.a/src/legacy/library/a/some.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/*!
* ${copyright}
*/
console.log('HelloWorld');
Empty file.
144 changes: 144 additions & 0 deletions test/lib/extensions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
const {test} = require("ava");
const path = require("path");
const projectPreprocessor = require("../..").projectPreprocessor;
const applicationAPath = path.join(__dirname, "..", "fixtures", "application.a");
const legacyLibraryAPath = path.join(__dirname, "..", "fixtures", "legacy.library.a");

test("Projects with extension dependency inline configuration", (t) => {
const tree = {
id: "application.a",
path: applicationAPath,
dependencies: [{
id: "extension.a",
path: applicationAPath,
dependencies: [],
version: "1.0.0",
specVersion: "0.1",
kind: "extension",
type: "project-shim",
metadata: {
name: "shims.a"
},
configurations: {
"legacy.library.a": {
specVersion: "0.1",
type: "library",
metadata: {
name: "legacy.library.a",
}
}
}
}, {
id: "legacy.library.a",
version: "1.0.0",
path: legacyLibraryAPath,
dependencies: []
}],
version: "1.0.0",
specVersion: "0.1",
type: "application",
metadata: {
name: "xy"
}
};
return projectPreprocessor.processTree(tree).then((parsedTree) => {
t.deepEqual(parsedTree, {
_level: 0,
type: "application",
metadata: {
name: "xy",
},
resources: {
configuration: {
paths: {
webapp: "webapp"
}
},
pathMappings: {
"/": "webapp",
}
},
dependencies: [{
id: "legacy.library.a",
kind: "project",
version: "1.0.0",
specVersion: "0.1",
path: legacyLibraryAPath,
_level: 1,
type: "library",
metadata: {
name: "legacy.library.a",
copyright: "${copyright}",
},
resources: {
configuration: {
paths: {
src: "src",
test: "test"
}
},
pathMappings: {
"/resources/": "src",
"/test-resources/": "test"
}
},
dependencies: []
}],
id: "application.a",
kind: "project",
version: "1.0.0",
specVersion: "0.1",
path: applicationAPath
}, "Parsed correctly");
});
});

test("Projects with extension dependency inline configuration", (t) => {
const tree = {
id: "application.a",
path: applicationAPath,
dependencies: [{
id: "extension.a",
path: applicationAPath,
dependencies: [],
version: "1.0.0",
specVersion: "0.1",
kind: "extension",
type: "project-type",
metadata: {
name: "z"
}
}],
version: "1.0.0",
specVersion: "0.1",
type: "z",
metadata: {
name: "xy"
}
};
return t.throws(projectPreprocessor.processTree(tree).then((parsedTree) => {
t.deepEqual(parsedTree, {
_level: 0,
type: "z",
metadata: {
name: "xy",
},
resources: {
configuration: {
paths: {
root: ""
}
},
pathMappings: {
"/": "",
}
},
dependencies: [],
id: "application.a",
kind: "project",
version: "1.0.0",
specVersion: "0.1",
path: applicationAPath
}, "Parsed correctly");
}), "Unknown extension type 'project-type' for extension.a", "Rejected with error");
});
52 changes: 1 addition & 51 deletions test/lib/projectPreprocessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,57 +48,6 @@ test("Project with inline configuration", (t) => {
});
});

test("Projects with extension dependency inline configuration", (t) => {
const tree = {
id: "application.a",
path: applicationAPath,
dependencies: [{
id: "extension.a",
path: applicationAPath,
dependencies: [],
version: "1.0.0",
specVersion: "0.1",
kind: "extension",
type: "project-type",
metadata: {
name: "z"
}
}],
version: "1.0.0",
specVersion: "0.1",
type: "application",
metadata: {
name: "xy"
}
};
return projectPreprocessor.processTree(tree).then((parsedTree) => {
t.deepEqual(parsedTree, {
_level: 0,
type: "application",
metadata: {
name: "xy",
},
resources: {
configuration: {
paths: {
webapp: "webapp"
}
},
pathMappings: {
"/": "webapp",
}
},
dependencies: [],
id: "application.a",
kind: "project",
version: "1.0.0",
specVersion: "0.1",
path: applicationAPath
}, "Parsed correctly");
});
});


test("Project with configPath", (t) => {
const tree = {
id: "application.a",
Expand Down Expand Up @@ -1036,6 +985,7 @@ test("Library version in package.json data is missing", (t) => {
const tree = {
id: "library.d",
path: libraryDPath,
dependencies: [],
type: "library",
metadata: {
name: "library.d"
Expand Down

0 comments on commit 93c9b39

Please sign in to comment.