Skip to content

Commit

Permalink
[FIX] generateResourcesJson: Add raw-module info for debug bundles (#736
Browse files Browse the repository at this point in the history
)

The raw-module info within .library is only maintained using the
non-debug name (module name).
Therefore, the analysis must use that name when running with debug bundles.

Furthermore the handling of the "module" property for debug resources
has been changed to only take place within the ResourceCollector.

JIRA: CPOUI5FOUNDATION-480
  • Loading branch information
matz3 committed Apr 25, 2022
1 parent 7bf2302 commit 3b918e8
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 23 deletions.
37 changes: 22 additions & 15 deletions lib/lbt/resources/ResourceCollector.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,11 @@ class ResourceCollector {
}

async enrichWithDependencyInfo(resourceInfo) {
return this._pool.getModuleInfo(resourceInfo.name).then(async (moduleInfo) => {
if ( moduleInfo.name ) {
return this._pool.getModuleInfo(resourceInfo.name, resourceInfo.module).then(async (moduleInfo) => {
if ( !resourceInfo.module && moduleInfo.name ) {
resourceInfo.module = moduleInfo.name;
}

if ( moduleInfo.dynamicDependencies ) {
resourceInfo.dynRequired = true;
}
Expand Down Expand Up @@ -279,37 +280,43 @@ class ResourceCollector {

await Promise.all(promises);

const debugBundlePromises = [];

for (let i = debugResourcesInfo.length - 1; i >= 0; i--) {
const dbgInfo = debugResourcesInfo[i];
const nonDebugName = ResourceInfoList.getNonDebugName(dbgInfo.name);
await Promise.all(debugResourcesInfo.map(async (dbgInfo) => {
const debugName = dbgInfo.name;
const nonDebugName = ResourceInfoList.getNonDebugName(debugName);
const nonDbgInfo = this._resources.get(nonDebugName);

// FIXME: "merged" property is only calculated in ResourceInfo#copyFrom
// Therefore using the same logic here to compute it.

// TODO: Idea: Use IsDebugVariant tag to decide whether to analyze the resource
// If the tag is set, we don't expect different analysis results so we can copy the info (else-path)
// Only when the tag is not set, we analyze the resource with its name (incl. -dbg)

if (!nonDbgInfo || (nonDbgInfo.included != null && nonDbgInfo.included.size > 0)) {
// We need to analyze the dbg resource if there is no non-dbg variant or
// it is a bundle because we will (usually) have different content.
debugBundlePromises.push(
this.enrichWithDependencyInfo(dbgInfo)
);

if (nonDbgInfo) {
// Always use the non-debug module name, if available
dbgInfo.module = nonDbgInfo.module;
}
await this.enrichWithDependencyInfo(dbgInfo);
} else {
// If the non-dbg resource is not a bundle, we can just copy over the info and skip
// analyzing the dbg variant as both should have the same info.

const newDbgInfo = new ResourceInfo(dbgInfo.name);
const newDbgInfo = new ResourceInfo(debugName);

// First copy info of analysis from non-dbg file (included, required, condRequired, ...)
newDbgInfo.copyFrom(null, nonDbgInfo);
// Then copy over info from dbg file to properly set name, isDebug, etc.
newDbgInfo.copyFrom(null, dbgInfo);
// Finally, set the module name to the non-dbg name
newDbgInfo.module = nonDbgInfo.module;

this._resources.set(dbgInfo.name, newDbgInfo);
this._resources.set(debugName, newDbgInfo);
}
}

await Promise.all(debugBundlePromises);
}));
}

createOrphanFilters() {
Expand Down
1 change: 0 additions & 1 deletion lib/lbt/resources/ResourceInfoList.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ class ResourceInfoList {
if ( myInfo == null ) {
myInfo = new ResourceInfo(relativeName);
myInfo.size = info.size;
myInfo.module = ResourceInfoList.getNonDebugName(info.name);
this.resources.push(myInfo);
this.resourcesByName.set(relativeName, myInfo);
}
Expand Down
13 changes: 7 additions & 6 deletions lib/lbt/resources/ResourcePool.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,17 +176,18 @@ class ResourcePool {
/**
* Retrieves the module info
*
* @param {string} name module name
* @param {string} resourceName resource/module name
* @param {string} [moduleName] module name, in case it differs from the resource name (e.g. for -dbg resources)
* @returns {Promise<ModuleInfo>}
*/
async getModuleInfo(name) {
let info = this._dependencyInfos.get(name);
async getModuleInfo(resourceName, moduleName) {
let info = this._dependencyInfos.get(resourceName);
if ( info == null ) {
info = Promise.resolve().then(async () => {
const resource = await this.findResource(name);
return determineDependencyInfo( resource, this._rawModuleInfos.get(name), this );
const resource = await this.findResource(resourceName);
return determineDependencyInfo( resource, this._rawModuleInfos.get(moduleName || resourceName), this );
});
this._dependencyInfos.set(name, info);
this._dependencyInfos.set(resourceName, info);
}
return info;
}
Expand Down
147 changes: 147 additions & 0 deletions test/lib/lbt/resources/ResourceCollector.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const test = require("ava");
const sinon = require("sinon");
const mock = require("mock-require");
const {Resource} = require("@ui5/fs");
const LocatorResourcePool = require("../../../../lib/lbt/resources/LocatorResourcePool");

let ResourceCollector = require("../../../../lib/lbt/resources/ResourceCollector");

Expand Down Expand Up @@ -286,3 +288,148 @@ test.serial("enrichWithDependencyInfo: add infos to resourceinfo", async (t) =>
requiresTopLevelScope: true
}, "all information gets used for the resourceInfo");
});

test.serial("integration: Raw Module Info for debug variant", async (t) => {
const resources = [
new Resource({
path: "/resources/mylib/myRawModuleBundle.js",
string: `define('a', () => 'a');define('b', ['a'], (a) => a + 'b');`
}),
new Resource({
path: "/resources/mylib/externalDependency.js",
string: `console.log('Foo');`
}),
new Resource({
path: "/resources/mylib/myRawModuleBundle-dbg.js",
string: `
define('a', () => 'a');
define('b', ['a'], (a) => a + 'b');
`
}),
new Resource({
path: "/resources/mylib/.library",
string: `
<?xml version="1.0" encoding="UTF-8" ?>
<library xmlns="http://www.sap.com/sap.ui.library.xsd">
<name>mylib</name>
<vendor>Me</vendor>
<copyright>mylib</copyright>
<version>1.0.0</version>
<documentation>mylib</documentation>
<dependencies>
<dependency>
<libraryName>sap.ui.core</libraryName>
</dependency>
</dependencies>
<appData>
<packaging xmlns="http://www.sap.com/ui5/buildext/packaging" version="2.0">
<module-infos>
<raw-module
name="mylib/myRawModuleBundle.js"
depends="mylib/externalDependency.js"
/>
</module-infos>
</packaging>
</appData>
</library>`
}),
];

const pool = new LocatorResourcePool();
await pool.prepare( resources );

const collector = new ResourceCollector(pool);
await Promise.all(resources.map((resource) => collector.visitResource(resource)));

await collector.determineResourceDetails({
debugResources: ["**/*-dbg.js"]
});

collector.groupResourcesByComponents();

const resourceInfoList = collector.components.get("mylib/");

const myRawModuleBundle = resourceInfoList.resourcesByName.get("myRawModuleBundle.js");
t.is(myRawModuleBundle.name, "myRawModuleBundle.js");
t.is(myRawModuleBundle.module, "mylib/myRawModuleBundle.js");
t.is(myRawModuleBundle.format, "raw");
t.is(myRawModuleBundle.requiresTopLevelScope, false);
t.deepEqual(myRawModuleBundle.included,
new Set(["a.js", "b.js"]));
t.deepEqual(myRawModuleBundle.required,
new Set(["mylib/externalDependency.js"]));

const myRawModuleBundleDbg = resourceInfoList.resourcesByName.get("myRawModuleBundle-dbg.js");
t.is(myRawModuleBundleDbg.name, "myRawModuleBundle-dbg.js");
t.is(myRawModuleBundleDbg.module, "mylib/myRawModuleBundle.js");
t.is(myRawModuleBundleDbg.format, "raw");
t.is(myRawModuleBundleDbg.requiresTopLevelScope, false);
t.deepEqual(myRawModuleBundleDbg.included,
new Set(["a.js", "b.js"]));
t.deepEqual(myRawModuleBundleDbg.required,
new Set(["mylib/externalDependency.js"]));
});

test.serial("integration: Analyze debug bundle", async (t) => {
const resources = [
new Resource({
path: "/resources/mylib/myBundle.js",
string: `sap.ui.predefine('a', () => 'a');sap.ui.predefine('b', ['a'], (a) => a + 'b');`
}),
new Resource({
path: "/resources/mylib/myBundle-dbg.js",
string: `sap.ui.predefine('a', () => 'a');`
}),
new Resource({
path: "/resources/mylib/.library",
string: `
<?xml version="1.0" encoding="UTF-8" ?>
<library xmlns="http://www.sap.com/sap.ui.library.xsd">
<name>mylib</name>
<vendor>Me</vendor>
<copyright>mylib</copyright>
<version>1.0.0</version>
<documentation>mylib</documentation>
<dependencies>
<dependency>
<libraryName>sap.ui.core</libraryName>
</dependency>
</dependencies>
</library>`
}),
];

const pool = new LocatorResourcePool();
await pool.prepare( resources );

const collector = new ResourceCollector(pool);
await Promise.all(resources.map((resource) => collector.visitResource(resource)));

await collector.determineResourceDetails({
debugResources: ["**/*-dbg.js"]
});

collector.groupResourcesByComponents();

const resourceInfoList = collector.components.get("mylib/");

const myRawModuleBundle = resourceInfoList.resourcesByName.get("myBundle.js");
t.is(myRawModuleBundle.name, "myBundle.js");
t.is(myRawModuleBundle.module, "mylib/myBundle.js");
t.is(myRawModuleBundle.format, null);
t.is(myRawModuleBundle.requiresTopLevelScope, false);
t.deepEqual(myRawModuleBundle.included,
new Set(["a.js", "b.js"]));
t.deepEqual(myRawModuleBundle.required,
new Set([]));

const myRawModuleBundleDbg = resourceInfoList.resourcesByName.get("myBundle-dbg.js");
t.is(myRawModuleBundleDbg.name, "myBundle-dbg.js");
t.is(myRawModuleBundleDbg.module, "mylib/myBundle.js");
t.is(myRawModuleBundleDbg.format, null);
t.is(myRawModuleBundleDbg.requiresTopLevelScope, false);
t.deepEqual(myRawModuleBundleDbg.included,
new Set(["a.js"]));
t.deepEqual(myRawModuleBundleDbg.required,
new Set());
});
3 changes: 2 additions & 1 deletion test/lib/lbt/resources/ResourceInfoList.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ test("add: add debug resources", (t) => {
t.is(resourceInfoList.resources.length, 1, "one resource added");

const resultDbg = resourceInfoList.resourcesByName.get("../myfile-dbg.js");
t.is(resultDbg.module, "myfile.js", "module is set");
// Note: "module" will be set properly for debug resources within ResourceCollector#determineResourceDetails
t.is(resultDbg.module, undefined, "module is not set");
t.deepEqual(resultDbg.required, new Set(["some-dep.js"]), "module is set");
});

Expand Down

0 comments on commit 3b918e8

Please sign in to comment.