Skip to content

Commit

Permalink
[FIX] generateResourcesJson: Analyze debug bundles (#669)
Browse files Browse the repository at this point in the history
  • Loading branch information
matz3 authored Jan 20, 2022
1 parent 02f9160 commit f27513a
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 41 deletions.
48 changes: 33 additions & 15 deletions lib/lbt/resources/ResourceCollector.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,17 +193,16 @@ class ResourceCollector {
}

async determineResourceDetails({
debugResources, mergedResources, designtimeResources, supportResources, debugBundles
debugResources, mergedResources, designtimeResources, supportResources
}) {
const baseNames = new Set();
const debugFilter = new ResourceFilterList(debugResources);
const mergeFilter = new ResourceFilterList(mergedResources);
const designtimeFilter = new ResourceFilterList(designtimeResources);
const supportFilter = new ResourceFilterList(supportResources);
const debugBundleFilter = new ResourceFilterList(debugBundles);

const promises = [];
const nonBundledDebugResources = [];
const debugResourcesInfo = [];

for (const [name, info] of this._resources.entries()) {
if ( debugFilter.matches(name) ) {
Expand Down Expand Up @@ -231,13 +230,14 @@ class ResourceCollector {
}

if ( /(?:\.js|\.view\.xml|\.control\.xml|\.fragment\.xml)$/.test(name) ) {
if ( (!info.isDebug || debugBundleFilter.matches(name)) ) {
// Only analyze non-debug files and special debug bundles (like sap-ui-core-dbg.js)
if ( !info.isDebug ) {
// Only analyze non-dbg files in first run
promises.push(
this.enrichWithDependencyInfo(info)
);
} else {
nonBundledDebugResources.push(info);
// Collect dbg files to be handled in a second step (see below)
debugResourcesInfo.push(info);
}
}

Expand Down Expand Up @@ -279,19 +279,37 @@ class ResourceCollector {

await Promise.all(promises);

for (let i = nonBundledDebugResources.length - 1; i >= 0; i--) {
const dbgInfo = nonBundledDebugResources[i];
const debugBundlePromises = [];

for (let i = debugResourcesInfo.length - 1; i >= 0; i--) {
const dbgInfo = debugResourcesInfo[i];
const nonDebugName = ResourceInfoList.getNonDebugName(dbgInfo.name);
const nonDbgInfo = this._resources.get(nonDebugName);
const newDbgInfo = new ResourceInfo(dbgInfo.name);

// 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);

this._resources.set(dbgInfo.name, newDbgInfo);
// FIXME: "merged" property is only calculated in ResourceInfo#copyFrom
// Therefore using the same logic here to compute it.
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)
);
} 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);

// 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);

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

await Promise.all(debugBundlePromises);
}

createOrphanFilters() {
Expand Down
18 changes: 2 additions & 16 deletions lib/processors/resourceListCreator.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,6 @@ const DEFAULT_SUPPORT_RESOURCES_FILTER = [
"**/*.support.js"
];

/**
* Hard coded debug bundle, to trigger separate analysis for this filename
* because sap-ui-core.js and sap-ui-core-dbg.js have different includes
*
* @type {string[]}
*/
const DEBUG_BUNDLES = [
"sap-ui-core-dbg.js",
"sap-ui-core-nojQuery-dbg.js"
];

/**
* Creates and adds resources.json entry (itself) to the list.
*
Expand Down Expand Up @@ -138,8 +127,7 @@ module.exports = async function({resources, dependencyResources = [], options})
debugResources: DEFAULT_DEBUG_RESOURCES_FILTER,
mergedResources: DEFAULT_BUNDLE_RESOURCES_FILTER,
designtimeResources: DEFAULT_DESIGNTIME_RESOURCES_FILTER,
supportResources: DEFAULT_SUPPORT_RESOURCES_FILTER,
debugBundles: DEBUG_BUNDLES
supportResources: DEFAULT_SUPPORT_RESOURCES_FILTER
}, options);

const pool = new LocatorResourcePool();
Expand All @@ -158,12 +146,10 @@ module.exports = async function({resources, dependencyResources = [], options})
}

await collector.determineResourceDetails({
pool,
debugResources: options.debugResources,
mergedResources: options.mergedResources,
designtimeResources: options.designtimeResources,
supportResources: options.supportResources,
debugBundles: options.debugBundles
supportResources: options.supportResources
});

// group resources by components and create ResourceInfoLists
Expand Down
54 changes: 44 additions & 10 deletions test/lib/lbt/resources/ResourceCollector.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ test.serial("visitResource: ensure proper matching of indicator files", async (t
t.is(resourceCollector.components.size, 0, "No prefixes should be added");
});

test.serial("groupResourcesByComponents: debugBundles", async (t) => {
test.serial("groupResourcesByComponents: external resources", async (t) => {
const resourceCollector = new ResourceCollector();
resourceCollector.setExternalResources({
"testcomp": ["my/file.js"]
Expand Down Expand Up @@ -149,25 +149,60 @@ test.serial("determineResourceDetails: view.xml", async (t) => {
t.is(enrichWithDependencyInfoStub.getCall(0).args[0].name, "mylib/my.view.xml", "is called with view");
});

test.serial("determineResourceDetails: Debug bundle", async (t) => {
test.serial("determineResourceDetails: Debug bundle (without non-debug variant)", async (t) => {
const resourceCollector = new ResourceCollector();

const enrichWithDependencyInfoStub = sinon.stub(resourceCollector, "enrichWithDependencyInfo").resolves();
await resourceCollector.visitResource({getPath: () => "/resources/MyBundle-dbg.js", getSize: async () => 13});

await resourceCollector.determineResourceDetails({
debugBundles: ["MyBundle-dbg.js"]
debugResources: ["**/*-dbg.js"], // MyBundle-dbg.js should be marked as "isDebug"
});

t.is(enrichWithDependencyInfoStub.callCount, 1, "enrichWithDependencyInfo is called once");
t.is(enrichWithDependencyInfoStub.getCall(0).args[0].name, "MyBundle-dbg.js",
"enrichWithDependencyInfo is called with debug bundle");
});

test.serial("determineResourceDetails: Debug bundle (with non-debug variant)", async (t) => {
const resourceCollector = new ResourceCollector();

const enrichWithDependencyInfoStub = sinon.stub(resourceCollector, "enrichWithDependencyInfo")
.onFirstCall().callsFake(async (resourceInfo) => {
resourceInfo.included = new Set(["SomeModule.js"]);
resourceInfo.required = new Set(["Boot.js"]);
})
.onSecondCall().callsFake(async (resourceInfo) => {
resourceInfo.required = new Set(["Boot.js"]);
});
await resourceCollector.visitResource({getPath: () => "/resources/MyBundle-dbg.js", getSize: async () => 13});
await resourceCollector.visitResource({getPath: () => "/resources/MyBundle.js", getSize: async () => 13});

await resourceCollector.determineResourceDetails({
debugResources: ["**/*-dbg.js"], // MyBundle-dbg.js should be marked as "isDebug"
});
t.is(enrichWithDependencyInfoStub.callCount, 2, "enrichWithDependencyInfo is called twice");
t.is(enrichWithDependencyInfoStub.getCall(0).args[0].name, "MyBundle.js",
"enrichWithDependencyInfo is called with non-debug bundle first");
t.is(enrichWithDependencyInfoStub.getCall(1).args[0].name, "MyBundle-dbg.js",
"enrichWithDependencyInfo is called with debug bundle on second run");

const bundleInfo = resourceCollector._resources.get("MyBundle.js");
t.deepEqual(bundleInfo.included, new Set(["SomeModule.js"]));
t.deepEqual(bundleInfo.required, new Set(["Boot.js"]));
t.is(bundleInfo.isDebug, false);

const debugBundleInfo = resourceCollector._resources.get("MyBundle-dbg.js");
t.is(debugBundleInfo.included, null);
t.deepEqual(debugBundleInfo.required, new Set(["Boot.js"]));
t.is(debugBundleInfo.isDebug, true);
});

test.serial("determineResourceDetails: Debug files and non-debug files", async (t) => {
const resourceCollector = new ResourceCollector();

const enrichWithDependencyInfoStub = sinon.stub(resourceCollector, "enrichWithDependencyInfo")
.callsFake((resourceInfo) => {
.callsFake(async (resourceInfo) => {
// Simulate enriching resource info with dependency info to test whether it gets shared
// with the dbg resource later on
resourceInfo.dynRequired = true;
Expand All @@ -183,16 +218,15 @@ test.serial("determineResourceDetails: Debug files and non-debug files", async (
}));

await resourceCollector.determineResourceDetails({
debugResources: ["**/*-dbg.js"],
debugBundles: ["MyBundle-dbg.js"]
debugResources: ["**/*-dbg.js"]
});
t.is(enrichWithDependencyInfoStub.callCount, 3, "enrichWithDependencyInfo is called three times");
t.is(enrichWithDependencyInfoStub.getCall(0).args[0].name, "MyBundle-dbg.js",
"enrichWithDependencyInfo called with debug bundle");
t.is(enrichWithDependencyInfoStub.getCall(1).args[0].name, "mylib/MyControlA.js",
t.is(enrichWithDependencyInfoStub.getCall(0).args[0].name, "mylib/MyControlA.js",
"enrichWithDependencyInfo called with non-debug control A");
t.is(enrichWithDependencyInfoStub.getCall(2).args[0].name, "mylib/MyControlB.js",
t.is(enrichWithDependencyInfoStub.getCall(1).args[0].name, "mylib/MyControlB.js",
"enrichWithDependencyInfo called with non-debug control B");
t.is(enrichWithDependencyInfoStub.getCall(2).args[0].name, "MyBundle-dbg.js",
"enrichWithDependencyInfo called with debug bundle");

t.is(resourceCollector._resources.get("MyBundle-dbg.js").isDebug, true, "MyBundle-dbg is a debug file");
t.is(resourceCollector._resources.get("MyBundle-dbg.js").dynRequired, true,
Expand Down

0 comments on commit f27513a

Please sign in to comment.