@ui5/task-adaptation 1.6.5-rc.3 → 1.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.test +1 -0
- package/CHANGELOG.md +10 -57
- package/README.md +4 -0
- package/dist/adapters/abapAdapter.d.ts +7 -5
- package/dist/adapters/abapAdapter.js +9 -11
- package/dist/adapters/adapter.d.ts +9 -5
- package/dist/adapters/adapter.js +20 -0
- package/dist/adapters/cfAdapter.d.ts +8 -5
- package/dist/adapters/cfAdapter.js +16 -10
- package/dist/adapters/commands/command.d.ts +26 -23
- package/dist/adapters/commands/command.js +73 -46
- package/dist/adapters/commands/fetchEndpointsCommand.d.ts +9 -0
- package/dist/adapters/commands/fetchEndpointsCommand.js +21 -0
- package/dist/adapters/commands/fetchPreviewResourcesCommand.d.ts +15 -0
- package/dist/adapters/commands/fetchPreviewResourcesCommand.js +102 -0
- package/dist/adapters/commands/filterFilesCommand.d.ts +4 -0
- package/dist/adapters/commands/filterFilesCommand.js +22 -0
- package/dist/adapters/commands/omitDeletedResourcesCommand.d.ts +10 -0
- package/dist/adapters/commands/omitDeletedResourcesCommand.js +31 -0
- package/dist/adapters/commands/processPreviewResourcesCommand.d.ts +9 -0
- package/dist/adapters/commands/processPreviewResourcesCommand.js +51 -0
- package/dist/adapters/commands/renameFilesCommand.d.ts +20 -0
- package/dist/{util/filesUtil.js → adapters/commands/renameFilesCommand.js} +34 -43
- package/dist/adapters/commands/writeResourcesCommand.d.ts +7 -0
- package/dist/adapters/commands/writeResourcesCommand.js +20 -0
- package/dist/adapters/commands/xsAppJsonEnhanceRoutesCommand.d.ts +3 -3
- package/dist/adapters/commands/xsAppJsonEnhanceRoutesCommand.js +4 -4
- package/dist/adapters/previewAdapter.d.ts +12 -6
- package/dist/adapters/previewAdapter.js +28 -7
- package/dist/{appVariantManager.d.ts → appVariant.d.ts} +2 -9
- package/dist/{appVariantManager.js → appVariant.js} +14 -26
- package/dist/{baseAppManager.js → baseApp.js} +6 -12
- package/dist/bundle.js +53 -12
- package/dist/cache/cacheHolder.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +34 -69
- package/dist/model/configuration.d.ts +1 -0
- package/dist/model/configuration.js +1 -0
- package/dist/model/types.d.ts +9 -2
- package/dist/repositories/localRepository.d.ts +2 -3
- package/dist/repositories/localRepository.js +54 -33
- package/dist/util/cf/xsAppJsonUtil.d.ts +16 -3
- package/dist/util/cf/xsAppJsonUtil.js +7 -18
- package/dist/util/commonUtil.d.ts +6 -0
- package/dist/util/commonUtil.js +17 -0
- package/dist/util/fsUtil.d.ts +1 -2
- package/dist/util/fsUtil.js +12 -33
- package/dist/util/renamingUtil.js +1 -1
- package/dist/util/resourceUtil.js +1 -1
- package/dist/util/validator/abapValidator.js +2 -2
- package/dist/util/validator/validator.d.ts +1 -0
- package/dist/util/validator/validator.js +11 -0
- package/package.json +11 -12
- package/.hyperspace/pull_request_bot.json +0 -19
- package/dist/previewManager.d.ts +0 -14
- package/dist/previewManager.js +0 -147
- package/dist/util/filesUtil.d.ts +0 -19
- package/scripts/metadataDownloadHelper.ts +0 -88
- package/scripts/publish.ts +0 -256
- package/scripts/test-integration-prep.sh +0 -4
- /package/dist/{baseAppManager.d.ts → baseApp.d.ts} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { trimExtension } from "./util/commonUtil.js";
|
|
2
|
+
import { validateAppId } from "./util/validator/validator.js";
|
|
2
3
|
const IGNORE_FILES = [
|
|
3
4
|
"manifest-bundle.zip",
|
|
4
5
|
"Component-preload.js",
|
|
@@ -72,22 +73,15 @@ export default class BaseApp {
|
|
|
72
73
|
}
|
|
73
74
|
return "i18n/i18n";
|
|
74
75
|
}
|
|
75
|
-
VALIDATION_RULES = new Map([["sap.app/id",
|
|
76
|
-
if (!value.includes(".")) {
|
|
77
|
-
// 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
|
|
78
|
-
// In the manifest.json file, make sure that the attribute
|
|
79
|
-
// sap.app/id has at least 2 segments.
|
|
80
|
-
throw new Error(`The original application id '${value}' should consist of multiple segments split by dot, e.g.: original.id`);
|
|
81
|
-
}
|
|
82
|
-
}]]);
|
|
76
|
+
VALIDATION_RULES = new Map([["sap.app/id", validateAppId]]);
|
|
83
77
|
validateProperty(value, property) {
|
|
84
78
|
if (!value) {
|
|
85
79
|
throw new Error(`Original application manifest should have ${property}`);
|
|
86
80
|
}
|
|
87
|
-
let
|
|
88
|
-
if (
|
|
89
|
-
|
|
81
|
+
let validationRule = this.VALIDATION_RULES.get(property);
|
|
82
|
+
if (validationRule) {
|
|
83
|
+
validationRule(value);
|
|
90
84
|
}
|
|
91
85
|
}
|
|
92
86
|
}
|
|
93
|
-
//# sourceMappingURL=
|
|
87
|
+
//# sourceMappingURL=baseApp.js.map
|
package/dist/bundle.js
CHANGED
|
@@ -6301,7 +6301,7 @@ class _URL extends URL {
|
|
|
6301
6301
|
}
|
|
6302
6302
|
}
|
|
6303
6303
|
|
|
6304
|
-
var rAmpersand = /&/g, rApplicationGroupID = /^\w+$/, sClassName$2 = "sap.ui.model.odata.v4.lib._Helper", rEquals = /\=/g, rGroupID = /^(\$auto(\.\w+)?|\$direct|\w+)$/, rHash = /#/g, rNotMetaContext = /\([^/]*|\/-?\d+/g, rPlus = /\+/g, rSingleQuote = /'/g, rSingleQuoteTwice = /''/g, rWhitespace = /\s+/g, _Helper;
|
|
6304
|
+
var rAmpersand = /&/g, rApplicationGroupID = /^\w+$/, sClassName$2 = "sap.ui.model.odata.v4.lib._Helper", rEndsWithTransientPredicate = /\(\$uid=[-\w]+\)$/, rEquals = /\=/g, rGroupID = /^(\$auto(\.\w+)?|\$direct|\w+)$/, rHash = /#/g, rNotMetaContext = /\([^/]*|\/-?\d+/g, rPlus = /\+/g, rSingleQuote = /'/g, rSingleQuoteTwice = /''/g, rWhitespace = /\s+/g, _Helper;
|
|
6305
6305
|
_Helper = {
|
|
6306
6306
|
addByPath: function (mMap, sPath, oItem) {
|
|
6307
6307
|
if (oItem) {
|
|
@@ -6495,6 +6495,19 @@ _Helper = {
|
|
|
6495
6495
|
convert(mQueryOptions, "");
|
|
6496
6496
|
return aPaths;
|
|
6497
6497
|
},
|
|
6498
|
+
copyETags: function (oSource, oTarget) {
|
|
6499
|
+
if (_Helper.getPrivateAnnotation(oSource, "predicate") !== _Helper.getPrivateAnnotation(oTarget, "predicate")) {
|
|
6500
|
+
return;
|
|
6501
|
+
}
|
|
6502
|
+
oTarget["@odata.etag"] = oSource["@odata.etag"];
|
|
6503
|
+
for (const sKey in oSource) {
|
|
6504
|
+
const vSourceProperty = oSource[sKey];
|
|
6505
|
+
const vTargetProperty = oTarget[sKey];
|
|
6506
|
+
if (vSourceProperty && vTargetProperty && typeof vSourceProperty === "object" && !Array.isArray(vSourceProperty)) {
|
|
6507
|
+
_Helper.copyETags(vSourceProperty, vTargetProperty);
|
|
6508
|
+
}
|
|
6509
|
+
}
|
|
6510
|
+
},
|
|
6498
6511
|
copyPrivateAnnotation: function (oSource, sAnnotation, oTarget, bAllowSame) {
|
|
6499
6512
|
if (_Helper.hasPrivateAnnotation(oSource, sAnnotation)) {
|
|
6500
6513
|
if (_Helper.hasPrivateAnnotation(oTarget, sAnnotation)) {
|
|
@@ -6540,6 +6553,10 @@ _Helper = {
|
|
|
6540
6553
|
if (typeof oResult.message === "object") {
|
|
6541
6554
|
oResult.message = oResult.error.message.value;
|
|
6542
6555
|
}
|
|
6556
|
+
const oClone = oResult.error["@$ui5.originalMessage"] = _Helper.clone(oResult.error);
|
|
6557
|
+
oResult.error.details?.forEach(function (oDetail, i) {
|
|
6558
|
+
oDetail["@$ui5.originalMessage"] = oClone.details[i];
|
|
6559
|
+
});
|
|
6543
6560
|
} catch (e) {
|
|
6544
6561
|
Log.warning(e.toString(), sBody, sClassName$2);
|
|
6545
6562
|
}
|
|
@@ -6583,7 +6600,7 @@ _Helper = {
|
|
|
6583
6600
|
};
|
|
6584
6601
|
},
|
|
6585
6602
|
createTechnicalDetails: function (oMessage) {
|
|
6586
|
-
var oClonedMessage, oError = oMessage["@$ui5.error"], oOriginalMessage = oMessage["@$ui5.originalMessage"]
|
|
6603
|
+
var oClonedMessage, oError = oMessage["@$ui5.error"], oOriginalMessage = oMessage["@$ui5.originalMessage"], oTechnicalDetails = {};
|
|
6587
6604
|
if (oError && (oError.status || oError.cause)) {
|
|
6588
6605
|
oError = oError.cause || oError;
|
|
6589
6606
|
oTechnicalDetails.httpStatus = oError.status;
|
|
@@ -6594,7 +6611,7 @@ _Helper = {
|
|
|
6594
6611
|
oTechnicalDetails.retryAfter = oError.retryAfter;
|
|
6595
6612
|
}
|
|
6596
6613
|
}
|
|
6597
|
-
if (
|
|
6614
|
+
if (oOriginalMessage) {
|
|
6598
6615
|
Object.defineProperty(oTechnicalDetails, "originalMessage", {
|
|
6599
6616
|
enumerable: true,
|
|
6600
6617
|
get: function () {
|
|
@@ -6709,9 +6726,11 @@ _Helper = {
|
|
|
6709
6726
|
message: oMessage.message,
|
|
6710
6727
|
numericSeverity: iNumericSeverity,
|
|
6711
6728
|
technical: bTechnical || oMessage.technical,
|
|
6712
|
-
"@$ui5.error": oError
|
|
6713
|
-
"@$ui5.originalMessage": oMessage
|
|
6729
|
+
"@$ui5.error": oError
|
|
6714
6730
|
};
|
|
6731
|
+
if (!(oMessage instanceof Error)) {
|
|
6732
|
+
oRawMessage["@$ui5.originalMessage"] = oMessage["@$ui5.originalMessage"] ?? oMessage;
|
|
6733
|
+
}
|
|
6715
6734
|
Object.keys(oMessage).forEach(function (sProperty) {
|
|
6716
6735
|
if (sProperty[0] === "@") {
|
|
6717
6736
|
if (sProperty.endsWith(".numericSeverity")) {
|
|
@@ -7016,6 +7035,28 @@ _Helper = {
|
|
|
7016
7035
|
}
|
|
7017
7036
|
return mURLParameters;
|
|
7018
7037
|
},
|
|
7038
|
+
getUsedPaths: function (aPaths, mQueryOptions) {
|
|
7039
|
+
function isRelated(sPath0, sPath1) {
|
|
7040
|
+
return _Helper.hasPathPrefix(sPath0, sPath1) || _Helper.hasPathPrefix(sPath1, sPath0);
|
|
7041
|
+
}
|
|
7042
|
+
function isUsed(sPath, mQueryOptionsForPath) {
|
|
7043
|
+
let bPathMatchedExpand = false;
|
|
7044
|
+
const aSelect = mQueryOptionsForPath.$select || ["*"];
|
|
7045
|
+
const mExpand = mQueryOptionsForPath.$expand || ({});
|
|
7046
|
+
return sPath === "*" || (sPath in mExpand) || aSelect.includes(sPath) || aSelect.some(sSelect => isRelated(sPath, sSelect)) || Object.keys(mExpand).some(sExpand => {
|
|
7047
|
+
if (_Helper.hasPathPrefix(sPath, sExpand)) {
|
|
7048
|
+
bPathMatchedExpand = true;
|
|
7049
|
+
return isUsed(sPath.slice(sExpand.length + 1), mExpand[sExpand]);
|
|
7050
|
+
}
|
|
7051
|
+
if (_Helper.hasPathPrefix(sExpand, sPath)) {
|
|
7052
|
+
bPathMatchedExpand = true;
|
|
7053
|
+
return true;
|
|
7054
|
+
}
|
|
7055
|
+
return false;
|
|
7056
|
+
}) || !bPathMatchedExpand && aSelect.includes("*");
|
|
7057
|
+
}
|
|
7058
|
+
return aPaths.filter(sPath => isUsed(sPath, mQueryOptions));
|
|
7059
|
+
},
|
|
7019
7060
|
hasPathPrefix: function (sPath, sBasePath) {
|
|
7020
7061
|
return _Helper.getRelativePath(sPath, sBasePath) !== undefined;
|
|
7021
7062
|
},
|
|
@@ -7134,6 +7175,9 @@ _Helper = {
|
|
|
7134
7175
|
}
|
|
7135
7176
|
return mResult;
|
|
7136
7177
|
},
|
|
7178
|
+
isAffectedBy: function (sPropertyPath, sSideEffectsPath) {
|
|
7179
|
+
return _Helper.hasPathPrefix(sPropertyPath, sSideEffectsPath.endsWith("/*") ? sSideEffectsPath.slice(0, -2) : sSideEffectsPath);
|
|
7180
|
+
},
|
|
7137
7181
|
isDataAggregation: function (mParameters) {
|
|
7138
7182
|
return mParameters && mParameters.$$aggregation && !mParameters.$$aggregation.hierarchyQualifier;
|
|
7139
7183
|
},
|
|
@@ -7190,13 +7234,7 @@ _Helper = {
|
|
|
7190
7234
|
return oURL.origin === new URL(document.baseURI).origin ? oURL.toString().slice(oURL.origin.length) : oURL.toString();
|
|
7191
7235
|
},
|
|
7192
7236
|
makeAbsoluteLongtextUrl: function (oMessage, sBase) {
|
|
7193
|
-
|
|
7194
|
-
const sAbsoluteLongtextURL = _Helper.makeAbsolute(oMessage.longtextUrl, sBase);
|
|
7195
|
-
if (oMessage.longtextUrl !== sAbsoluteLongtextURL) {
|
|
7196
|
-
oMessage["@$ui5.originalMessage"] ??= _Helper.clone(oMessage);
|
|
7197
|
-
oMessage.longtextUrl = sAbsoluteLongtextURL;
|
|
7198
|
-
}
|
|
7199
|
-
}
|
|
7237
|
+
oMessage.longtextUrl &&= _Helper.makeAbsolute(oMessage.longtextUrl, sBase);
|
|
7200
7238
|
},
|
|
7201
7239
|
makeRelativePath: function (sPath, sBase) {
|
|
7202
7240
|
return new _URL(sPath).relativeTo(new _URL(sBase));
|
|
@@ -7212,6 +7250,9 @@ _Helper = {
|
|
|
7212
7250
|
return oResult;
|
|
7213
7251
|
}, vValue);
|
|
7214
7252
|
},
|
|
7253
|
+
matchEndsWithTransientPredicate: function (sPath) {
|
|
7254
|
+
return rEndsWithTransientPredicate.exec(sPath);
|
|
7255
|
+
},
|
|
7215
7256
|
merge: fnMerge,
|
|
7216
7257
|
mergeQueryOptions: function (mQueryOptions, sOrderby, aFilters) {
|
|
7217
7258
|
var mResult;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export default class CacheHolder {
|
|
2
2
|
private static TEMP_TASK_DIR;
|
|
3
|
-
|
|
3
|
+
static getTempDir(...paths: string[]): string;
|
|
4
4
|
static read(repoName: string, token: string): Promise<Map<string, string>>;
|
|
5
5
|
static write(repoName: string, token: string, files: Map<string, string>): Promise<void>;
|
|
6
6
|
private static isValid;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ import { ITaskParameters } from "./model/types.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Creates an appVariant bundle from the provided resources.
|
|
4
4
|
*/
|
|
5
|
-
declare const _default: ({ workspace, options, taskUtil }: ITaskParameters) => Promise<
|
|
5
|
+
declare const _default: ({ workspace, options, taskUtil }: ITaskParameters) => Promise<ReadonlyMap<string, string>>;
|
|
6
6
|
export default _default;
|
package/dist/index.js
CHANGED
|
@@ -1,79 +1,44 @@
|
|
|
1
1
|
import * as dotenv from "dotenv";
|
|
2
|
-
import { logBuilderVersion } from "./util/commonUtil.js";
|
|
3
|
-
import AppVariant from "./
|
|
4
|
-
import BaseApp from "./
|
|
5
|
-
import ResourceUtil from "./util/resourceUtil.js";
|
|
6
|
-
import FilesUtil from "./util/filesUtil.js";
|
|
7
|
-
import PreviewManager from "./previewManager.js";
|
|
2
|
+
import { getReferences, logBuilderVersion } from "./util/commonUtil.js";
|
|
3
|
+
import AppVariant from "./appVariant.js";
|
|
4
|
+
import BaseApp from "./baseApp.js";
|
|
8
5
|
import { initialize } from "./landscapeConfiguration.js";
|
|
9
6
|
/**
|
|
10
7
|
* Creates an appVariant bundle from the provided resources.
|
|
11
8
|
*/
|
|
12
|
-
export default ({ workspace, options, taskUtil }) => {
|
|
9
|
+
export default async ({ workspace, options, taskUtil }) => {
|
|
10
|
+
const ui5BuilderTools = {
|
|
11
|
+
workspace,
|
|
12
|
+
projectNamespace: options.projectNamespace,
|
|
13
|
+
taskUtil,
|
|
14
|
+
};
|
|
13
15
|
dotenv.config();
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
// appVariantIdHierarchy contains original application on bottom and the
|
|
24
|
-
// latest app variant on top. We reverse the list to process original
|
|
25
|
-
// application first and then app variants in chronological order.
|
|
26
|
-
const reversedHierarchy = appVariantIdHierarchy.toReversed();
|
|
27
|
-
const fetchFilesPromises = reversedHierarchy.map(variant => repository.fetch(variant));
|
|
28
|
-
fetchFilesPromises.push(Promise.resolve(adaptationProject.files));
|
|
29
|
-
const appVariants = new Array();
|
|
30
|
-
const adapt = async (baseAppFiles, appVariantFiles) => {
|
|
31
|
-
let baseApp = BaseApp.fromFiles(baseAppFiles);
|
|
32
|
-
let appVariant = AppVariant.fromFiles(appVariantFiles);
|
|
33
|
-
// If the app variant is the same as the adaptation project, we use the
|
|
34
|
-
// adaptation project because it contains resources that should be updated.
|
|
35
|
-
if (appVariant.id === adaptationProject.id) {
|
|
36
|
-
appVariant = adaptationProject;
|
|
37
|
-
}
|
|
38
|
-
appVariants.push(appVariant);
|
|
39
|
-
const adaptCommandChain = adapter.createAdaptCommandChain(baseApp, appVariant);
|
|
40
|
-
const mergeCommandChain = adapter.createMergeCommandChain(baseApp, appVariant);
|
|
41
|
-
const adaptedFiles = await adaptCommandChain.execute();
|
|
42
|
-
const mergedFiles = await mergeCommandChain.execute(adaptedFiles);
|
|
43
|
-
return mergedFiles;
|
|
44
|
-
};
|
|
45
|
-
let files = await fetchFilesPromises.reduce(async (previousFiles, currentFiles) => adapt(await previousFiles, await currentFiles), fetchFilesPromises.shift());
|
|
46
|
-
files = await adapter.createPostCommandChain().execute(files);
|
|
47
|
-
const references = getReferences(appVariants, adaptationProject.id);
|
|
48
|
-
files = FilesUtil.filter(files);
|
|
49
|
-
files = FilesUtil.rename(files, references);
|
|
50
|
-
adaptationProject.omitDeletedResources(files, options.projectNamespace, taskUtil);
|
|
51
|
-
// Read libs for preview
|
|
52
|
-
const previewManager = await previewManagerPromise;
|
|
53
|
-
const writePromises = new Array(previewManager.processPreviewResources(files));
|
|
54
|
-
files.forEach((content, filename) => {
|
|
55
|
-
const resource = ResourceUtil.createResource(filename, options.projectNamespace, content);
|
|
56
|
-
writePromises.push(workspace.write(resource));
|
|
57
|
-
});
|
|
58
|
-
await Promise.all(writePromises);
|
|
16
|
+
logBuilderVersion();
|
|
17
|
+
const { repository, adapter } = initialize(options.configuration);
|
|
18
|
+
const adaptationProject = await AppVariant.fromWorkspace(workspace, options.projectNamespace);
|
|
19
|
+
const setupCommandChain = adapter.createSetupCommandChain(adaptationProject.reference, repository);
|
|
20
|
+
await setupCommandChain.execute();
|
|
21
|
+
const appVariantIdHierarchy = await repository.getAppVariantIdHierarchy(adaptationProject.reference);
|
|
22
|
+
if (appVariantIdHierarchy.length === 0) {
|
|
23
|
+
throw new Error(`No app variant found for reference ${adaptationProject.reference}`);
|
|
59
24
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
appVariants.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
variant.getRenamingForMovedFiles().forEach((value, key) => references.set(key, value));
|
|
75
|
-
});
|
|
76
|
-
return references;
|
|
25
|
+
// appVariantIdHierarchy contains original application on bottom and the
|
|
26
|
+
// latest app variant on top. We reverse the list to process original
|
|
27
|
+
// application first and then app variants in chronological order.
|
|
28
|
+
const reversedHierarchy = appVariantIdHierarchy.toReversed();
|
|
29
|
+
const fetchFilesPromises = reversedHierarchy.map(variant => repository.fetch(variant));
|
|
30
|
+
const appVariants = new Array();
|
|
31
|
+
const adapt = async (baseFiles, appVariant) => {
|
|
32
|
+
appVariants.push(appVariant);
|
|
33
|
+
const baseApp = BaseApp.fromFiles(baseFiles);
|
|
34
|
+
return adapter.createAdaptCommandChain(baseApp, appVariant).execute();
|
|
35
|
+
};
|
|
36
|
+
let files = await fetchFilesPromises.shift(); // original app files
|
|
37
|
+
for (const appVariantFiles of fetchFilesPromises) {
|
|
38
|
+
files = await adapt(files, AppVariant.fromFiles(await appVariantFiles));
|
|
77
39
|
}
|
|
40
|
+
files = await adapt(files, adaptationProject);
|
|
41
|
+
const references = getReferences(appVariants, adaptationProject.id);
|
|
42
|
+
return adapter.createPostCommandChain(references, adaptationProject, ui5BuilderTools).execute(files);
|
|
78
43
|
};
|
|
79
44
|
//# sourceMappingURL=index.js.map
|
package/dist/model/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import TaskUtil from "@ui5/project/build/helpers/TaskUtil";
|
|
1
2
|
import { IConfiguration } from "./configuration.js";
|
|
2
3
|
import Language from "./language.js";
|
|
3
4
|
export interface IProjectOptions {
|
|
@@ -74,9 +75,14 @@ export interface IChangeContent {
|
|
|
74
75
|
supportedLocales?: string[];
|
|
75
76
|
}
|
|
76
77
|
export interface ITaskParameters {
|
|
77
|
-
workspace:
|
|
78
|
+
workspace: IWorkspace;
|
|
78
79
|
options: IProjectOptions;
|
|
79
|
-
taskUtil:
|
|
80
|
+
taskUtil: TaskUtil;
|
|
81
|
+
}
|
|
82
|
+
export interface UI5BuilderTools {
|
|
83
|
+
workspace: IWorkspace;
|
|
84
|
+
projectNamespace: string;
|
|
85
|
+
taskUtil: TaskUtil;
|
|
80
86
|
}
|
|
81
87
|
export interface IBaseAppInfo {
|
|
82
88
|
filepath: string;
|
|
@@ -123,4 +129,5 @@ export type ServiceCredentials = {
|
|
|
123
129
|
} | string>;
|
|
124
130
|
"sap.cloud.service"?: string;
|
|
125
131
|
};
|
|
132
|
+
export type FetchFilesPromise = Map<string, Promise<ReadonlyMap<string, string>>>;
|
|
126
133
|
export { IConfiguration };
|
|
@@ -7,7 +7,6 @@ export default class LocalRepository implements IRepository {
|
|
|
7
7
|
downloadAnnotationFile(_uri: string): Promise<Map<string, string>>;
|
|
8
8
|
getAppVariantIdHierarchy(appId: string): Promise<ILocalResource[]>;
|
|
9
9
|
fetch(resource: ILocalResource): Promise<Map<string, string>>;
|
|
10
|
-
private
|
|
11
|
-
private
|
|
12
|
-
private getLocalFilesDirectory;
|
|
10
|
+
private buildManifestIndex;
|
|
11
|
+
private getLocalFilesDir;
|
|
13
12
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getLogger } from "@ui5/logger";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
|
+
import { glob } from "glob";
|
|
4
5
|
import FsUtil from "../util/fsUtil.js";
|
|
5
6
|
const log = getLogger("@ui5/task-adaptation::LocalRepository");
|
|
6
7
|
export default class LocalRepository {
|
|
@@ -10,48 +11,68 @@ export default class LocalRepository {
|
|
|
10
11
|
}
|
|
11
12
|
async getAppVariantIdHierarchy(appId) {
|
|
12
13
|
const items = [];
|
|
13
|
-
|
|
14
|
+
const baseDir = this.getLocalFilesDir();
|
|
15
|
+
const index = await this.buildManifestIndex(baseDir);
|
|
16
|
+
const visited = new Set();
|
|
17
|
+
let currentAppId = appId;
|
|
18
|
+
while (currentAppId) {
|
|
19
|
+
if (visited.has(currentAppId)) {
|
|
20
|
+
throw new Error(`Cycle detected in app variant hierarchy: '${currentAppId}' was already visited. Visited IDs: ${[...visited].join(" -> ")} -> ${currentAppId}`);
|
|
21
|
+
}
|
|
22
|
+
visited.add(currentAppId);
|
|
23
|
+
const entry = index.get(currentAppId);
|
|
24
|
+
if (!entry) {
|
|
25
|
+
throw new Error(`App '${currentAppId}' not found in local directory '${baseDir}'.`);
|
|
26
|
+
}
|
|
27
|
+
items.push({
|
|
28
|
+
appName: currentAppId,
|
|
29
|
+
cacheBusterToken: Promise.resolve("local"),
|
|
30
|
+
absolutePath: entry.absolutePath,
|
|
31
|
+
});
|
|
32
|
+
if (entry.isVariant) {
|
|
33
|
+
if (!entry.reference || typeof entry.reference !== "string") {
|
|
34
|
+
throw new Error(`Invalid or missing 'reference' for app variant '${currentAppId}': expected a non-empty string but got '${entry.reference}'`);
|
|
35
|
+
}
|
|
36
|
+
currentAppId = entry.reference;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
currentAppId = undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
14
42
|
return items;
|
|
15
43
|
}
|
|
16
44
|
fetch(resource) {
|
|
17
45
|
log.verbose(`Fetching base app files from local directory: ${resource.absolutePath}`);
|
|
18
46
|
return FsUtil.readFilesRecursively(resource.absolutePath);
|
|
19
47
|
}
|
|
20
|
-
async
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (existingManifestPath.endsWith("manifest.appdescr_variant")) {
|
|
36
|
-
const manifestContent = await fs.readFile(existingManifestPath, "utf-8");
|
|
37
|
-
const manifest = JSON.parse(manifestContent);
|
|
38
|
-
await this.collectAppVariantIdHierarchyItems(manifest.reference, items);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
async getExistingManifestPath(filePaths) {
|
|
42
|
-
const existenceChecks = await Promise.all(filePaths.map((filePath) => FsUtil.exists(filePath)));
|
|
43
|
-
const existingIndex = existenceChecks.findIndex((exists) => exists);
|
|
44
|
-
if (existingIndex !== -1) {
|
|
45
|
-
return filePaths[existingIndex];
|
|
48
|
+
async buildManifestIndex(baseDir) {
|
|
49
|
+
const index = new Map();
|
|
50
|
+
const manifestPaths = await glob("**/manifest.{json,appdescr_variant}", { cwd: baseDir, absolute: true, dot: true });
|
|
51
|
+
for (const manifestPath of manifestPaths) {
|
|
52
|
+
const content = await fs.readFile(manifestPath, "utf-8");
|
|
53
|
+
const manifest = JSON.parse(content);
|
|
54
|
+
const isVariant = manifestPath.endsWith("manifest.appdescr_variant");
|
|
55
|
+
const id = isVariant ? manifest.id : manifest["sap.app"]?.id;
|
|
56
|
+
if (typeof id === "string" && id) {
|
|
57
|
+
index.set(id, {
|
|
58
|
+
absolutePath: path.dirname(manifestPath),
|
|
59
|
+
reference: manifest.reference,
|
|
60
|
+
isVariant,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
46
63
|
}
|
|
47
|
-
|
|
64
|
+
return index;
|
|
48
65
|
}
|
|
49
|
-
|
|
66
|
+
getLocalFilesDir() {
|
|
50
67
|
const adpDirConfigured = process.env.ADP_BUILDER_DIR;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
68
|
+
if (adpDirConfigured) {
|
|
69
|
+
const unix = adpDirConfigured.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
70
|
+
if (/^[A-Za-z]:/.test(adpDirConfigured) || path.isAbsolute(unix)) {
|
|
71
|
+
return unix;
|
|
72
|
+
}
|
|
73
|
+
return path.join(process.cwd(), unix);
|
|
74
|
+
}
|
|
75
|
+
throw new Error("Environment variable 'ADP_BUILDER_DIR' is not set. Please set it to the directory containing the local app files.");
|
|
55
76
|
}
|
|
56
77
|
}
|
|
57
78
|
//# sourceMappingURL=localRepository.js.map
|
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ServiceCredentials } from "../../model/types.js";
|
|
2
|
+
export type XsApp = {
|
|
3
|
+
welcomeFile?: string;
|
|
4
|
+
authenticationMethod: "none" | "route";
|
|
5
|
+
routes: Route[];
|
|
6
|
+
};
|
|
7
|
+
export type Route = {
|
|
8
|
+
source: string;
|
|
9
|
+
target: string;
|
|
10
|
+
service?: string;
|
|
11
|
+
destination?: string;
|
|
12
|
+
authenticationType?: string;
|
|
13
|
+
localDir?: string;
|
|
14
|
+
};
|
|
2
15
|
export declare const XSAPP_JSON_FILENAME = "xs-app.json";
|
|
3
16
|
/**
|
|
4
17
|
* Merges multiple xs-app.json contents into one. AppVariant and Reuse Library
|
|
@@ -10,5 +23,5 @@ export declare const XSAPP_JSON_FILENAME = "xs-app.json";
|
|
|
10
23
|
*/
|
|
11
24
|
export declare function merge(xsAppFiles: string[]): string | undefined;
|
|
12
25
|
export declare function enhanceRoutesWithEndpointAndService(xsAppJsonContent: string, serviceCredentials: ServiceCredentials): string;
|
|
13
|
-
export declare function enhanceRoutes(serviceCredentials: ServiceCredentials, baseRoutes:
|
|
14
|
-
export declare function fetchCredentialsAndEnhanceRoutes(xsAppJson: string,
|
|
26
|
+
export declare function enhanceRoutes(serviceCredentials: ServiceCredentials, baseRoutes: Route[]): Route[];
|
|
27
|
+
export declare function fetchCredentialsAndEnhanceRoutes(xsAppJson: string, serviceCredentialsPromise: Promise<ServiceCredentials | undefined>): Promise<string>;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getLogger } from "@ui5/logger";
|
|
2
|
-
import CFUtil from "../cfUtil.js";
|
|
3
2
|
const log = getLogger("@ui5/task-adaptation::XSAppJsonUtil");
|
|
4
3
|
export const XSAPP_JSON_FILENAME = "xs-app.json";
|
|
5
4
|
/**
|
|
@@ -63,7 +62,7 @@ export function enhanceRoutes(serviceCredentials, baseRoutes) {
|
|
|
63
62
|
return acc;
|
|
64
63
|
}, {});
|
|
65
64
|
return baseRoutes.map((route) => {
|
|
66
|
-
const endpointName = destinationToEndpoint[route.destination];
|
|
65
|
+
const endpointName = route.destination && destinationToEndpoint[route.destination];
|
|
67
66
|
if (endpointName) {
|
|
68
67
|
// There is a matching endpoint: remove destination and add endpoint/service
|
|
69
68
|
const { destination: _destination, ...rest } = route;
|
|
@@ -79,22 +78,12 @@ export function enhanceRoutes(serviceCredentials, baseRoutes) {
|
|
|
79
78
|
}
|
|
80
79
|
});
|
|
81
80
|
}
|
|
82
|
-
export async function fetchCredentialsAndEnhanceRoutes(xsAppJson,
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
export async function fetchCredentialsAndEnhanceRoutes(xsAppJson, serviceCredentialsPromise) {
|
|
82
|
+
const serviceCredentials = await serviceCredentialsPromise;
|
|
83
|
+
if (!serviceCredentials) {
|
|
84
|
+
log.verbose(`No service credentials available. Skipping xs-app.json update.`);
|
|
85
|
+
return xsAppJson;
|
|
85
86
|
}
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
// Get valid service keys with proper endpoints structure
|
|
89
|
-
serviceCredentials = await CFUtil.getOrCreateServiceKeyWithEndpoints(serviceInstanceName, space);
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
throw new Error(`Failed to get valid service keys for app '${appName}': ${error.message}`);
|
|
93
|
-
}
|
|
94
|
-
if (serviceCredentials) {
|
|
95
|
-
return enhanceRoutesWithEndpointAndService(xsAppJson, serviceCredentials);
|
|
96
|
-
}
|
|
97
|
-
log.info(`No endpoints found for app '${appName}'. xs-app.json will not be updated.`);
|
|
98
|
-
return xsAppJson;
|
|
87
|
+
return enhanceRoutesWithEndpointAndService(xsAppJson, serviceCredentials);
|
|
99
88
|
}
|
|
100
89
|
//# sourceMappingURL=xsAppJsonUtil.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { IConfiguration } from "../model/types.js";
|
|
2
2
|
import Language from "../model/language.js";
|
|
3
|
+
import AppVariant from "../appVariant.js";
|
|
3
4
|
export declare function dotToUnderscore(value: string): string;
|
|
4
5
|
export declare function validateConfiguration<T extends object>(options: T, properties: Array<keyof T>): void;
|
|
5
6
|
export declare function validateObject<T extends object>(options: T, properties: Array<keyof T>, message: string): void;
|
|
@@ -12,3 +13,8 @@ export declare function logBuilderVersion(): void;
|
|
|
12
13
|
export declare function logBetaUsage(): void;
|
|
13
14
|
export declare function getUniqueName(existingNames: string[], template: string): string;
|
|
14
15
|
export declare function isManifestChange(filename: string, content: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* 4p. Reference map contains searchTerm as key and replacement as value. Base
|
|
18
|
+
* id and app variant ids are renamed to adaptation project id.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getReferences(appVariants: AppVariant[], adaptationProjectId: string): Map<string, string>;
|
package/dist/util/commonUtil.js
CHANGED
|
@@ -98,4 +98,21 @@ export function isManifestChange(filename, content) {
|
|
|
98
98
|
}
|
|
99
99
|
return false;
|
|
100
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* 4p. Reference map contains searchTerm as key and replacement as value. Base
|
|
103
|
+
* id and app variant ids are renamed to adaptation project id.
|
|
104
|
+
*/
|
|
105
|
+
export function getReferences(appVariants, adaptationProjectId) {
|
|
106
|
+
const references = new Map();
|
|
107
|
+
appVariants.forEach((variant, i) => {
|
|
108
|
+
if (i === 0) {
|
|
109
|
+
references.set(variant.reference, adaptationProjectId);
|
|
110
|
+
}
|
|
111
|
+
if (variant.id !== adaptationProjectId) {
|
|
112
|
+
references.set(variant.id, adaptationProjectId);
|
|
113
|
+
}
|
|
114
|
+
variant.getRenamingForMovedFiles().forEach((value, key) => references.set(key, value));
|
|
115
|
+
});
|
|
116
|
+
return references;
|
|
117
|
+
}
|
|
101
118
|
//# sourceMappingURL=commonUtil.js.map
|
package/dist/util/fsUtil.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export default class FsUtil {
|
|
2
|
-
static readInProject(filepath: string): Promise<string>;
|
|
2
|
+
static readInProject(filepath: string, encoding?: BufferEncoding): Promise<Buffer | string>;
|
|
3
3
|
/**
|
|
4
4
|
* Check whether a file or directory exists (non-throwing).
|
|
5
5
|
* @param filePath Absolute or relative path
|
|
@@ -7,5 +7,4 @@ export default class FsUtil {
|
|
|
7
7
|
*/
|
|
8
8
|
private static fileExists;
|
|
9
9
|
static readFilesRecursively(rootDirectory: string): Promise<Map<string, string>>;
|
|
10
|
-
static exists(filePath: string): Promise<boolean>;
|
|
11
10
|
}
|
package/dist/util/fsUtil.js
CHANGED
|
@@ -7,9 +7,9 @@ export default class FsUtil {
|
|
|
7
7
|
* @param filepath The relative file path from the project root (e.g. 'ui5AppInfo.json').
|
|
8
8
|
* @returns A promise that resolves to the file content as a string.
|
|
9
9
|
*/
|
|
10
|
-
static async readInProject(filepath) {
|
|
10
|
+
static async readInProject(filepath, encoding) {
|
|
11
11
|
try {
|
|
12
|
-
return await fs.readFile(path.join(process.cwd(), filepath),
|
|
12
|
+
return await fs.readFile(path.join(process.cwd(), filepath), encoding);
|
|
13
13
|
}
|
|
14
14
|
catch (error) {
|
|
15
15
|
const isProjectRoot = await FsUtil.fileExists(path.join(process.cwd(), "ui5.yaml"));
|
|
@@ -37,38 +37,17 @@ export default class FsUtil {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
static async readFilesRecursively(rootDirectory) {
|
|
40
|
-
const
|
|
41
|
-
const fileReadTasks =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (entry.isDirectory()) {
|
|
51
|
-
directoriesToScan.push(entryPath);
|
|
52
|
-
}
|
|
53
|
-
else if (entry.isFile()) {
|
|
54
|
-
fileReadTasks.push((async () => {
|
|
55
|
-
const relativeFilePath = path.relative(rootDirectory, entryPath);
|
|
56
|
-
const content = await fs.readFile(entryPath, "utf-8");
|
|
57
|
-
return [relativeFilePath, content];
|
|
58
|
-
})());
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
40
|
+
const entries = await fs.readdir(rootDirectory, { withFileTypes: true, recursive: true });
|
|
41
|
+
const fileReadTasks = entries
|
|
42
|
+
.filter(entry => entry.isFile())
|
|
43
|
+
.map(async (entry) => {
|
|
44
|
+
const parentPath = entry.parentPath ?? entry.path; // node v20.11.0 fallback
|
|
45
|
+
const entryPath = path.join(parentPath, entry.name);
|
|
46
|
+
const relativeFilePath = path.relative(rootDirectory, entryPath).replaceAll("\\", "/");
|
|
47
|
+
const content = await fs.readFile(entryPath, "utf-8");
|
|
48
|
+
return [relativeFilePath, content];
|
|
49
|
+
});
|
|
62
50
|
return new Map(await Promise.all(fileReadTasks));
|
|
63
51
|
}
|
|
64
|
-
static async exists(filePath) {
|
|
65
|
-
try {
|
|
66
|
-
await fs.access(filePath);
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
52
|
}
|
|
74
53
|
//# sourceMappingURL=fsUtil.js.map
|