builder/lib/tasks/bundlers/generateFlexChangesBundle.js

import {getLogger} from "@ui5/logger";
const log = getLogger("builder:tasks:bundlers:generateFlexChangesBundle");
import flexChangesBundler from "../../processors/bundlers/flexChangesBundler.js";
import semver from "semver";

/**
 * @public
 * @module @ui5/builder/tasks/bundlers/generateFlexChangesBundle
 */

/* eslint "jsdoc/check-param-names": ["error", {"disableExtraPropertyReporting":true}] */
/**
 * Task to create changesBundle.json file containing all changes stored in the /changes folder for easier consumption
 * at runtime.
 * If a change bundle is created, "sap.ui.fl" is added as a dependency to the manifest.json if not already present -
 * if the dependency is already listed but lazy-loaded, lazy loading is disabled.
 * If minUI5Version >= 1.73 flexibility-bundle.json will be create.
 * If there are control variants and minUI5Version < 1.73 build will break and throw an error.
 *
 * @public
 * @function default
 * @static
 *
 * @param {object} parameters Parameters
 * @param {@ui5/fs/DuplexCollection} parameters.workspace DuplexCollection to read and write files
 * @param {@ui5/project/build/helpers/TaskUtil|object} [parameters.taskUtil] TaskUtil
 * @param {object} [parameters.options] Options
 * @param {string} [parameters.options.projectNamespace] Project Namespace
 * @returns {Promise<undefined>} Promise resolving with <code>undefined</code> once data has been written
 */
export default async function({workspace, taskUtil, options = {}}) {
	// Backward compatibility: "namespace" option got renamed to "projectNamespace"
	const namespace = options.projectNamespace || options.namespace;

	// Use the given namespace if available, otherwise use no namespace
	// (e.g. in case no manifest.json is present)
	let pathPrefix = "";
	if (namespace) {
		pathPrefix = `/resources/${namespace}`;
	}

	function updateJson(data) {
		// ensure the existence of the libs section in the dependencies
		data["sap.ui5"] = data["sap.ui5"] || {};
		data["sap.ui5"].dependencies = data["sap.ui5"].dependencies || {};
		const mLibs = data["sap.ui5"].dependencies.libs = data["sap.ui5"].dependencies.libs || {};

		if (mLibs["sap.ui.fl"]) {
			log.verbose("sap.ui.fl found in manifest.json");
			if (mLibs["sap.ui.fl"].lazy) {
				log.verbose("sap.ui.fl 'lazy' attribute found in manifest.json, setting it to false...");
				mLibs["sap.ui.fl"].lazy = false;
			}
		} else {
			log.verbose("sap.ui.fl not found in manifest.json, inserting it...");
			mLibs["sap.ui.fl"] = {};
		}
	}

	async function updateFLdependency() {
		const manifestResource = await workspace.byPath(`${pathPrefix}/manifest.json`);
		const manifestContent = JSON.parse(await manifestResource.getString());

		updateJson(manifestContent);
		manifestResource.setString(JSON.stringify(manifestContent, null, "\t"));

		await workspace.write(manifestResource);
	}

	async function readManifestMinUI5Version() {
		const manifestResource = await workspace.byPath(`${pathPrefix}/manifest.json`);
		const manifestContent = JSON.parse(await manifestResource.getString());

		manifestContent["sap.ui5"] = manifestContent["sap.ui5"] || {};
		manifestContent["sap.ui5"].dependencies = manifestContent["sap.ui5"].dependencies || {};
		if (!Array.isArray(manifestContent["sap.ui5"].dependencies.minUI5Version)) {
			manifestContent["sap.ui5"].dependencies.minUI5Version =
				[manifestContent["sap.ui5"].dependencies.minUI5Version] || [""];
		}
		return manifestContent["sap.ui5"].dependencies.minUI5Version;
	}

	log.verbose("Collecting flexibility changes");
	const allResources = await workspace.byGlob(
		`${pathPrefix}/changes/*.{change,variant,ctrl_variant,ctrl_variant_change,ctrl_variant_management_change}`);
	if (allResources.length > 0) {
		const versionArray = await readManifestMinUI5Version();
		const versions = versionArray.map((version) => semver.coerce(version));
		const versionsAllSuitableForFlexBundle = versions.every((version) => semver.compare(version, "1.73.0") >= 0);
		let hasFlexBundleVersion = false;
		let flexBundle = {};
		if (versionsAllSuitableForFlexBundle) {
			hasFlexBundleVersion = true;
			const flexBundleResource = await workspace.byPath(`${pathPrefix}/changes/flexibility-bundle.json`);
			if (flexBundleResource) {
				flexBundle = JSON.parse(await flexBundleResource.getString());
			}
		}
		const processedResources = await flexChangesBundler({
			resources: allResources,
			options: {
				pathPrefix,
				hasFlexBundleVersion
			},
			existingFlexBundle: flexBundle
		});
		await Promise.all(processedResources.map((resource) => {
			log.verbose("Writing flexibility changes bundle");
			return workspace.write(resource);
		}));
		// Add the sap.ui.fl dependency if a bundle has been created
		if (processedResources.length > 0) {
			await updateFLdependency();
		}

		// Do not write bundled source files to build result
		if (taskUtil) {
			allResources.forEach((resource) => {
				taskUtil.setTag(resource, taskUtil.STANDARD_TAGS.OmitFromBuildResult);
			});
		}
	}
}