Skip to content

Commit

Permalink
improve code
Browse files Browse the repository at this point in the history
use typedef for ArtifactInfo instead of class
because functionality could be extracted and
it served then only as a data container.

replaced Object.keys().forEach loops which Object.entries loop

Use getResolvedLibraries for directly resolving transitive dependencies
  • Loading branch information
tobiasso85 committed Jan 22, 2021
1 parent b9da72d commit fd6a8e9
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 114 deletions.
162 changes: 49 additions & 113 deletions lib/processors/versionInfoGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ const processManifest = async (manifestResource) => {
const manifestDependencies = manifestObject["sap.ui5"]["dependencies"];
if (manifestDependencies) {
const libs = {};
Object.keys(manifestDependencies.libs).forEach((libKey) => {
for (const [libKey, libValue] of Object.entries(manifestDependencies.libs)) {
libs[libKey] = {};
if (manifestDependencies.libs[libKey].lazy) {
if (libValue.lazy) {
libs[libKey].lazy = true;
}
});
}
manifestInfo.libs = libs;
}
}
Expand Down Expand Up @@ -140,8 +140,8 @@ const getManifestPath = (filePath, subPath) => {

/**
* Represents dependency information for a library.
* Dependencies can be resolved recursively using <code>#resolve</code>
* and are stored then in <code>libsResolved</code>
* Dependencies can be retrieved using <code>#getResolvedLibraries</code>
* and with that are resolved recursively
*/
class DependencyInfo {
/**
Expand All @@ -152,14 +152,6 @@ class DependencyInfo {
constructor(libs, name) {
this.libs = libs;
this.name = name;

/**
* contains as key the library name and as value an object with an optional lazy property
*
* @type {ManifestLibraries}
*/
this.libsResolved = Object.create(null);
this.wasResolved = false;
}

/**
Expand All @@ -171,13 +163,13 @@ class DependencyInfo {
* @returns {{lazy: boolean}} the added library
*/
addResolvedLibDependency(libName, lazy) {
let alreadyResolved = this.libsResolved[libName];
let alreadyResolved = this._libsResolved[libName];
if (!alreadyResolved) {
alreadyResolved = Object.create(null);
if (lazy) {
alreadyResolved.lazy = true;
}
this.libsResolved[libName] = alreadyResolved;
this._libsResolved[libName] = alreadyResolved;
} else {
// siblings if sibling is eager only if one other sibling eager
alreadyResolved.lazy = alreadyResolved.lazy && lazy;
Expand All @@ -186,38 +178,38 @@ class DependencyInfo {
}

/**
* Resolves dependencies recursively and stores them in libsResolved
* with
* Resolves dependencies recursively and retrieves them with
* - resolved siblings a lazy and a eager dependency becomes eager
* - resolved children become lazy if their parent is lazy
*
* @param {Map<string,DependencyInfo>} dependencyInfoMap
* @returns {ManifestLibraries} resolved libraries
*/
resolve(dependencyInfoMap) {
if (!this.wasResolved) {
getResolvedLibraries(dependencyInfoMap) {
if (!this._libsResolved) {
// early set if there is a potential cycle
this.wasResolved = true;
Object.keys(this.libs).forEach((libName) => {
const lazy = this.libs[libName].lazy;
this._libsResolved = Object.create(null);
for (const [libName, libValue] of Object.entries(this.libs)) {
const lazy = libValue.lazy;
const dependencyInfoObjectAdded = this.addResolvedLibDependency(libName, lazy);
const dependencyInfo = dependencyInfoMap.get(libName);
if (dependencyInfo) {
dependencyInfo.resolve(dependencyInfoMap);
const childLibsResolved = dependencyInfo.getResolvedLibraries(dependencyInfoMap);

// children if parent is lazy children become lazy
Object.keys(dependencyInfo.libsResolved).forEach((resolvedLibName) => {
const resolvedLib = dependencyInfo.libsResolved[resolvedLibName];
for (const [resolvedLibName, resolvedLib] of Object.entries(childLibsResolved)) {
this.addResolvedLibDependency(resolvedLibName,
resolvedLib.lazy || dependencyInfoObjectAdded.lazy);
});
}
} else {
log.info(`Cannot find dependency '${libName}' `+
`defined in the manifest.json or .library file of project '${this.name}'. ` +
"This might prevent some UI5 runtime performance optimizations from taking effect. " +
"Please double check your project's dependency configuration.");
}
});
}
}
return this._libsResolved;
}
}

Expand All @@ -226,7 +218,7 @@ class DependencyInfo {
* Sorts the keys of a given object
*
* @param {object} obj the object
* @returns {{}} the object with sorted keys
* @returns {object} the object with sorted keys
*/
const sortObjectKeys = (obj) => {
const sortedObject = {};
Expand All @@ -242,78 +234,33 @@ const sortObjectKeys = (obj) => {
* Builds the manifestHints object from the dependencyInfo
*
* @param {DependencyInfo} dependencyInfo
* @param {Map<string, DependencyInfo>} dependencyInfoMap
* @returns {{dependencies: {libs: ManifestLibraries}}} manifestHints
*/
const getManifestHints = (dependencyInfo) => {
if (dependencyInfo && Object.keys(dependencyInfo.libsResolved).length) {
return {
dependencies: {
libs: sortObjectKeys(dependencyInfo.libsResolved)
}
};
const getManifestHints = (dependencyInfo, dependencyInfoMap) => {
if (dependencyInfo) {
const libsResolved = dependencyInfo.getResolvedLibraries(dependencyInfoMap);
if (libsResolved && Object.keys(libsResolved).length) {
return {
dependencies: {
libs: sortObjectKeys(libsResolved)
}
};
}
}
};

/**
* Common type for Library and Component
* embeds and bundled components makes only sense for library
*
* @typedef {object} ArtifactInfo
* @property {string} componentName The library name, e.g. "lib.x"
* @property {Set<string>} bundledComponents The embedded components which have a embeddedBy reference to the library
* @property {DependencyInfo} dependencyInfo The dependency info object
* @property {ArtifactInfo[]} embeds The embedded artifact infos
*/
class ArtifactInfo {
/**
* @param {string} componentName e.g. lib.x
*/
constructor(componentName) {
this.componentName = componentName;
this.artifactInfos = [];
this.parentBundledComponents = new Set();
}

/**
*
* @param {DependencyInfo} dependencyInfo
*/
setDependencyInfo(dependencyInfo) {
this.dependencyInfo = dependencyInfo;
}

/**
* The embedded components which have a embeddedBy reference to the library
*
* @param {Set<string>} bundledComponents e.g. ["lib.x.sub"]
*/
setBundledComponents(bundledComponents) {
this.bundledComponents = bundledComponents;
}

/**
* Set the embedded components of the library
*
* @param {ArtifactInfo[]} artifactInfos embedded components
*/
setEmbeds(artifactInfos) {
this.artifactInfos = artifactInfos;
this.artifactInfos.forEach((artifactInfo) => {
artifactInfo._setParent(this);
});
}

/**
* @returns {ArtifactInfo[]} get embedded components of this library
*/
getEmbeds() {
return this.artifactInfos;
}

/**
* @param {ArtifactInfo} parent set the parent library
* @private
*/
_setParent(parent) {
this.parent = parent;
this.parentBundledComponents = this.parent.bundledComponents;
this.parentComponentName = this.parent.componentName;
}
}

/**
* Processes the manifest and creates a ManifestInfo and an ArtifactInfo.
Expand All @@ -325,8 +272,9 @@ class ArtifactInfo {
async function processManifestAndGetArtifactInfo(libraryManifest, name) {
const manifestInfo = await processManifest(libraryManifest);
name = name || manifestInfo.id;
const libraryArtifactInfo = new ArtifactInfo(name);
libraryArtifactInfo.setDependencyInfo(new DependencyInfo(manifestInfo.libs, name));
const libraryArtifactInfo = Object.create(null);
libraryArtifactInfo.componentName = name;
libraryArtifactInfo.dependencyInfo = new DependencyInfo(manifestInfo.libs, name);
return {manifestInfo, libraryArtifactInfo};
}

Expand All @@ -347,7 +295,7 @@ const processLibraryInfo = async (libraryInfo) => {
await processManifestAndGetArtifactInfo(libraryInfo.libraryManifest, libraryInfo.name);

const bundledComponents = new Set();
libraryArtifactInfo.setBundledComponents(bundledComponents);
libraryArtifactInfo.bundledComponents = bundledComponents;

const embeds = manifestInfo.embeds; // e.g. ["sub"]
// filter only embedded manifests
Expand Down Expand Up @@ -378,7 +326,7 @@ const processLibraryInfo = async (libraryInfo) => {
});

const embeddedArtifactInfos = await Promise.all(embeddedManifestPromises);
libraryArtifactInfo.setEmbeds(embeddedArtifactInfos);
libraryArtifactInfo.embeds = embeddedArtifactInfos;

return libraryArtifactInfo;
};
Expand Down Expand Up @@ -434,29 +382,18 @@ module.exports = async function({options}) {


// process library infos
const librariesPromises = options.libraryInfos.map((libraryInfo) => {
const libraryInfosProcessPromises = options.libraryInfos.map((libraryInfo) => {
return processLibraryInfo(libraryInfo);
});

let artifactInfos = await Promise.all(librariesPromises);
let artifactInfos = await Promise.all(libraryInfosProcessPromises);
artifactInfos = artifactInfos.filter(Boolean);

// fill dependencyInfoMap
artifactInfos.forEach((artifactInfo) => {
dependencyInfoMap.set(artifactInfo.componentName, artifactInfo.dependencyInfo);
});

// resolve library dependencies (transitive)
dependencyInfoMap.forEach((dependencyInfo) => {
dependencyInfo.resolve(dependencyInfoMap);
});

// resolve dependencies of embedded components
artifactInfos.forEach((artifactInfo) => {
artifactInfo.getEmbeds().forEach((embeddedArtifactInfo) => {
embeddedArtifactInfo.dependencyInfo.resolve(dependencyInfoMap);
});
});

const libraries = options.libraryInfos.map((libraryInfo) => {
const library = {
Expand All @@ -467,7 +404,7 @@ module.exports = async function({options}) {
};

const dependencyInfo = dependencyInfoMap.get(libraryInfo.name);
const manifestHints = getManifestHints(dependencyInfo);
const manifestHints = getManifestHints(dependencyInfo, dependencyInfoMap);
if (manifestHints) {
library.manifestHints = manifestHints;
}
Expand All @@ -482,17 +419,16 @@ module.exports = async function({options}) {
// components
let components;
artifactInfos.forEach((artifactInfo) => {
artifactInfo.getEmbeds().forEach((embeddedArtifactInfo) => {
artifactInfo.embeds.forEach((embeddedArtifactInfo) => {
const componentObject = {
library: embeddedArtifactInfo.parentComponentName
library: artifactInfo.componentName
};
const componentName = embeddedArtifactInfo.componentName;
const dependencyInfo = embeddedArtifactInfo.dependencyInfo;
const manifestHints = getManifestHints(dependencyInfo);
const manifestHints = getManifestHints(embeddedArtifactInfo.dependencyInfo, dependencyInfoMap);
if (manifestHints) {
componentObject.manifestHints = manifestHints;
}
const bundledComponents = embeddedArtifactInfo.parentBundledComponents;
const bundledComponents = artifactInfo.bundledComponents;
if (bundledComponents.has(componentName)) {
componentObject.hasOwnPreload = true;
}
Expand Down
3 changes: 2 additions & 1 deletion test/lib/processors/versionInfoGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ test.serial("versionInfoGenerator library infos with dependencies", async (t) =>
"minUI5Version": "1.84",
"libs": {
"my.dep": {
"minVersion": "1.84.0"
"minVersion": "1.84.0",
"lazy": false
}
}
}
Expand Down

0 comments on commit fd6a8e9

Please sign in to comment.