@ui5/task-adaptation
Version:
Custom task for ui5-builder which allows building UI5 Flexibility Adaptation Projects for SAP BTP, Cloud Foundry environment
159 lines • 7.11 kB
JavaScript
import { AppDescriptorChange, Applier, RegistrationBuild } from "../dist/bundle.js";
import { trimExtension } from "./util/commonUtil.js";
import BuildStrategy from "./buildStrategy.js";
import { getLogger } from "@ui5/logger";
const log = getLogger("@ui5/task-adaptation::BaseAppManager");
const IGNORE_FILES = [
"manifest-bundle.zip",
"Component-preload.js",
"sap-ui-cachebuster-info.json"
];
/**
* Processes files to replace .js file content with corresponding -dbg.js
* content and remove -dbg.js
* @param files - Map of all files
* @returns Map with .js files replaced by -dbg.js content where applicable
*/
export function preProcessFiles(files) {
const processedFiles = new Map(files);
// Find all -dbg.js files that have corresponding .js files
for (const [filename, content] of files) {
if (filename.endsWith("-dbg.js")) {
const correspondingJsFile = filename.replace("-dbg.js", ".js");
if (files.has(correspondingJsFile)) {
// Replace the .js file content with the -dbg.js content
processedFiles.set(correspondingJsFile, content);
processedFiles.delete(filename);
}
}
else if (filename.endsWith("-dbg.js.map")) {
const correspondingJsFile = filename.replace("-dbg.js.map", ".js");
if (files.has(correspondingJsFile)) {
processedFiles.delete(filename);
}
}
if (IGNORE_FILES.some(ignoredFile => ignoredFile === filename)) {
processedFiles.delete(filename);
}
}
return processedFiles;
}
export default class BaseApp {
id;
version;
i18nPath;
files;
static fromFiles(files) {
return new BaseApp(files);
}
constructor(files) {
this.files = preProcessFiles(files);
const manifestString = files.get("manifest.json");
if (!manifestString) {
throw new Error("Original application should have manifest.json in root folder");
}
const manifest = JSON.parse(manifestString);
this.id = manifest["sap.app"]?.id;
this.version = manifest["sap.app"]?.applicationVersion?.version;
this.validateProperty(this.id, "sap.app/id");
this.validateProperty(this.version, "sap.app/applicationVersion/version");
this.i18nPath = this.extractI18nPathFromManifest(this.id, manifest["sap.app"]?.i18n);
}
async adapt(appVariant, processor) {
const files = new Map(this.files);
const manifest = JSON.parse(files.get("manifest.json"));
manifest["sap.app"].id = appVariant.id;
await processor.updateLandscapeSpecificContent(manifest, files, appVariant.id, appVariant.prefix);
this.updateComponentName(manifest, this.id);
this.fillAppVariantIdHierarchy(processor, appVariant.reference, this.version, manifest);
this.updateAdaptationProperties(manifest);
await this.applyDescriptorChanges(manifest, appVariant);
files.set("manifest.json", JSON.stringify(manifest));
return files;
}
updateComponentName(manifest, id) {
if (manifest["sap.ui5"] == null) {
manifest["sap.ui5"] = {};
}
if (manifest["sap.ui5"].componentName == null) {
manifest["sap.ui5"].componentName = id;
}
}
updateAdaptationProperties(content) {
if (content["sap.fiori"]?.cloudDevAdaptationStatus) {
delete content["sap.fiori"].cloudDevAdaptationStatus;
}
if (content["sap.ui5"] == null) {
content["sap.ui5"] = {};
}
content["sap.ui5"].isCloudDevAdaptation = true;
}
extractI18nPathFromManifest(sapAppId, i18nNode) {
if (i18nNode) {
if (i18nNode["bundleUrl"]) {
return trimExtension(i18nNode["bundleUrl"]);
}
else if (i18nNode["bundleName"]) {
return i18nNode["bundleName"].replace(sapAppId, "").replaceAll(".", "/").substring(1);
}
else if (typeof i18nNode === "string") {
return trimExtension(i18nNode);
}
}
return "i18n/i18n";
}
VALIDATION_RULES = new Map([["sap.app/id", (value) => {
if (!value.includes(".")) {
// https://help.sap.com/docs/bas/developing-sap-fiori-app-in-sap-business-application-studio/releasing-sap-fiori-application-to-be-extensible-in-adaptation-projects-on-sap-s-4hana-cloud
// In the manifest.json file, make sure that the attribute
// sap.app/id has at least 2 segments.
throw new Error(`The original application id '${value}' should consist of multiple segments split by dot, e.g.: original.id`);
}
}]]);
validateProperty(value, property) {
if (!value) {
throw new Error(`Original application manifest should have ${property}`);
}
let validatationRule = this.VALIDATION_RULES.get(property);
if (validatationRule) {
validatationRule(value);
}
}
async applyDescriptorChanges(baseAppManifest, appVariant) {
log.verbose("Applying appVariant changes");
const changesContent = new Array();
const i18nBundleName = appVariant.prefix;
for (const change of appVariant.getProcessedManifestChanges()) {
changesContent.push(new AppDescriptorChange(change));
this.adjustAddNewModelEnhanceWith(change, i18nBundleName);
}
if (changesContent.length > 0) {
const strategy = new BuildStrategy(RegistrationBuild);
await Applier.applyChanges(baseAppManifest, changesContent, strategy);
}
}
fillAppVariantIdHierarchy(processor, id, version, baseAppManifest) {
log.verbose("Filling up app variant hierarchy in manifest.json");
if (baseAppManifest["sap.ui5"] == null) {
baseAppManifest["sap.ui5"] = {};
}
if (baseAppManifest["sap.ui5"].appVariantIdHierarchy == null) {
baseAppManifest["sap.ui5"].appVariantIdHierarchy = [];
}
const appVariantIdHierarchyItem = processor.createAppVariantHierarchyItem(id, version);
baseAppManifest["sap.ui5"].appVariantIdHierarchy.unshift(appVariantIdHierarchyItem);
}
adjustAddNewModelEnhanceWith(change, i18nBundleName) {
if (change.changeType === "appdescr_ui5_addNewModelEnhanceWith") {
if (change.texts == null) {
// We need to add texts properties to changes because not all
// have texts property. Changes without texts property can
// causes issues in bundle.js This is needed for now, and will
// be removed as soon as change merger in openUI5 is updated
change.texts = { i18n: change.content?.bundleUrl || "i18n/i18n.properties" };
}
change.texts.i18n = i18nBundleName + "/" + change.texts.i18n;
}
}
}
//# sourceMappingURL=baseAppManager.js.map