@ui5/task-adaptation 1.3.1 → 1.3.2
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/CHANGELOG.md +5 -1
- package/dist/annotationManager.d.ts +18 -0
- package/dist/annotationManager.js +79 -0
- package/dist/annotations/comparator/comparator.d.ts +47 -0
- package/dist/annotations/comparator/comparator.js +283 -0
- package/dist/annotations/comparator/diffCase.d.ts +4 -0
- package/dist/annotations/comparator/diffCase.js +2 -0
- package/dist/annotations/comparator/interchangableCase.d.ts +25 -0
- package/dist/annotations/comparator/interchangableCase.js +60 -0
- package/dist/annotations/converter/metadataJsonReferenceUtil.d.ts +12 -0
- package/dist/annotations/converter/metadataJsonReferenceUtil.js +48 -0
- package/dist/annotations/converter/metadataJsonUtil.d.ts +30 -0
- package/dist/annotations/converter/metadataJsonUtil.js +70 -0
- package/dist/annotations/converter/ui5JsonConverter.d.ts +21 -0
- package/dist/annotations/converter/ui5JsonConverter.js +252 -0
- package/dist/annotations/converter/ui5MetadataJsonUtil.d.ts +3 -0
- package/dist/annotations/converter/ui5MetadataJsonUtil.js +10 -0
- package/dist/annotations/converter/ui5XmlConverter.d.ts +5 -0
- package/dist/annotations/converter/ui5XmlConverter.js +14 -0
- package/dist/annotations/dataSource/dataSource.d.ts +34 -0
- package/dist/annotations/dataSource/dataSource.js +62 -0
- package/dist/annotations/dataSource/dataSourceManager.d.ts +12 -0
- package/dist/annotations/dataSource/dataSourceManager.js +45 -0
- package/dist/annotations/dataSource/dataSourceOData.d.ts +17 -0
- package/dist/annotations/dataSource/dataSourceOData.js +45 -0
- package/dist/annotations/dataSource/dataSourceODataAnnotation.d.ts +6 -0
- package/dist/annotations/dataSource/dataSourceODataAnnotation.js +16 -0
- package/dist/annotations/serviceRequestor.d.ts +9 -0
- package/dist/annotations/serviceRequestor.js +73 -0
- package/dist/annotations/transformers/convertV2ToV4.d.ts +4 -0
- package/dist/annotations/transformers/convertV2ToV4.js +13 -0
- package/dist/annotations/transformers/makeAnnotationNamespaceUnique.d.ts +6 -0
- package/dist/annotations/transformers/makeAnnotationNamespaceUnique.js +41 -0
- package/dist/annotations/transformers/removeAllSchemaNodesExceptAnnotations.d.ts +4 -0
- package/dist/annotations/transformers/removeAllSchemaNodesExceptAnnotations.js +14 -0
- package/dist/annotations/transformers/transformer.d.ts +12 -0
- package/dist/annotations/transformers/transformer.js +2 -0
- package/dist/annotations/transformers/traverseReferences.d.ts +9 -0
- package/dist/annotations/transformers/traverseReferences.js +66 -0
- package/dist/appVariantManager.d.ts +12 -0
- package/dist/appVariantManager.js +102 -0
- package/dist/baseAppManager.d.ts +29 -0
- package/dist/baseAppManager.js +139 -0
- package/dist/buildStrategy.d.ts +7 -0
- package/dist/buildStrategy.js +19 -0
- package/dist/bundle.d.ts +25 -0
- package/dist/bundle.js +6975 -0
- package/dist/cache/annotationsCacheManager.d.ts +8 -0
- package/dist/cache/annotationsCacheManager.js +16 -0
- package/dist/cache/baseAppFilesCacheManager.d.ts +6 -0
- package/dist/cache/baseAppFilesCacheManager.js +12 -0
- package/dist/cache/cacheManager.d.ts +16 -0
- package/dist/cache/cacheManager.js +65 -0
- package/dist/i18nManager.d.ts +43 -0
- package/dist/i18nManager.js +203 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +25 -0
- package/dist/model/annotationDiffStructureError.d.ts +3 -0
- package/dist/model/annotationDiffStructureError.js +8 -0
- package/dist/model/language.d.ts +13 -0
- package/dist/model/language.js +37 -0
- package/dist/model/noAuthorizationProvidedError.d.ts +3 -0
- package/dist/model/noAuthorizationProvidedError.js +6 -0
- package/dist/model/serverError.d.ts +3 -0
- package/dist/model/serverError.js +6 -0
- package/dist/model/types.d.ts +119 -0
- package/dist/model/types.js +2 -0
- package/dist/processors/abapProcessor.d.ts +21 -0
- package/dist/processors/abapProcessor.js +37 -0
- package/dist/processors/cfProcessor.d.ts +17 -0
- package/dist/processors/cfProcessor.js +45 -0
- package/dist/processors/processor.d.ts +7 -0
- package/dist/processors/processor.js +32 -0
- package/dist/repositories/abapRepoManager.d.ts +13 -0
- package/dist/repositories/abapRepoManager.js +82 -0
- package/dist/repositories/html5RepoManager.d.ts +11 -0
- package/dist/repositories/html5RepoManager.js +87 -0
- package/dist/util/cfUtil.d.ts +30 -0
- package/dist/util/cfUtil.js +171 -0
- package/dist/util/commonUtil.d.ts +13 -0
- package/dist/util/commonUtil.js +118 -0
- package/dist/util/i18nMerger.d.ts +32 -0
- package/dist/util/i18nMerger.js +99 -0
- package/dist/util/requestUtil.d.ts +8 -0
- package/dist/util/requestUtil.js +54 -0
- package/dist/util/resourceUtil.d.ts +11 -0
- package/dist/util/resourceUtil.js +62 -0
- package/dist/util/urlUtil.d.ts +4 -0
- package/dist/util/urlUtil.js +18 -0
- package/dist/util/xmlUtil.d.ts +4 -0
- package/dist/util/xmlUtil.js +21 -0
- package/dist/util/zipUtil.d.ts +2 -0
- package/dist/util/zipUtil.js +16 -0
- package/package.json +2 -2
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import AnnotationsCacheManager from "../cache/annotationsCacheManager.js";
|
|
8
|
+
import ServerError from "../model/serverError.js";
|
|
9
|
+
import { getLogger } from "@ui5/logger";
|
|
10
|
+
import { writeTempAnnotations } from "../util/commonUtil.js";
|
|
11
|
+
const log = getLogger("@ui5/task-adaptation::ServiceRequestor");
|
|
12
|
+
function retryOnError(maxRetries) {
|
|
13
|
+
return (_target, _propertyKey, descriptor) => {
|
|
14
|
+
const originalMethod = descriptor.value;
|
|
15
|
+
descriptor.value = async function (...args) {
|
|
16
|
+
let retries = 0;
|
|
17
|
+
while (true) {
|
|
18
|
+
try {
|
|
19
|
+
return await originalMethod.apply(this, args);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (error instanceof ServerError) {
|
|
23
|
+
if (retries === maxRetries) {
|
|
24
|
+
throw new Error(`Error occurred: ${error.message}. Please try again if this is a temporary issue. If not, please create a ticket on CA-UI5-ABA-AIDX`);
|
|
25
|
+
}
|
|
26
|
+
retries++;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
throw new Error(`Failed to fetch annotation by '${args[0]}': ${error.message}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
return descriptor;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export default class ServiceRequestor {
|
|
38
|
+
abapRepoManager;
|
|
39
|
+
configuration;
|
|
40
|
+
constructor(configuration, abapRepoManager) {
|
|
41
|
+
this.abapRepoManager = abapRepoManager;
|
|
42
|
+
this.configuration = configuration;
|
|
43
|
+
}
|
|
44
|
+
//@ts-ignore tsx (esbuild) is not yet implemented the new decorators, but
|
|
45
|
+
//old decorators are already subject of compiler error, but it works. So we
|
|
46
|
+
//wait till esbuild implement it correctly.
|
|
47
|
+
async downloadAnnotation(uri, name, language) {
|
|
48
|
+
let cacheName = name;
|
|
49
|
+
if (language.sap) {
|
|
50
|
+
uri += `?sap-language=${language.sap}`;
|
|
51
|
+
cacheName += `-${language.sap}`;
|
|
52
|
+
}
|
|
53
|
+
const cacheManager = new AnnotationsCacheManager(this.configuration, cacheName);
|
|
54
|
+
log.verbose(`Getting annotation '${cacheName}' ${language} by '${uri}'`);
|
|
55
|
+
let files;
|
|
56
|
+
if (this.configuration.enableAnnotationCache) {
|
|
57
|
+
files = await cacheManager.getFiles(() => this.abapRepoManager.getAnnotationMetadata(uri), () => this.abapRepoManager.downloadAnnotationFile(uri));
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
files = await this.abapRepoManager.downloadAnnotationFile(uri);
|
|
61
|
+
}
|
|
62
|
+
if (!files || files.size === 0) {
|
|
63
|
+
throw new Error(`No files were fetched for '${name}' by '${uri}'`);
|
|
64
|
+
}
|
|
65
|
+
const xml = [...files][0][1];
|
|
66
|
+
writeTempAnnotations(this.configuration, name, language, xml);
|
|
67
|
+
return xml;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
__decorate([
|
|
71
|
+
retryOnError(1)
|
|
72
|
+
], ServiceRequestor.prototype, "downloadAnnotation", null);
|
|
73
|
+
//# sourceMappingURL=serviceRequestor.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import MetadataJsonUtil from "../converter/metadataJsonUtil.js";
|
|
2
|
+
import UI5JsonConverter from "../converter/ui5JsonConverter.js";
|
|
3
|
+
import UI5XmlConverter from "../converter/ui5XmlConverter.js";
|
|
4
|
+
export default class ConvertV2ToV4 {
|
|
5
|
+
transform({ json, xml }) {
|
|
6
|
+
if (MetadataJsonUtil.getVersion(json) !== "4.0") {
|
|
7
|
+
const annotationsV4 = UI5JsonConverter.convertAnnotations(UI5XmlConverter.convertV2(xml));
|
|
8
|
+
MetadataJsonUtil.setAnnotations(json, annotationsV4);
|
|
9
|
+
}
|
|
10
|
+
return json;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=convertV2ToV4.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import MetadataJsonUtil from "../converter/metadataJsonUtil.js";
|
|
2
|
+
import crc16 from "crc/crc16";
|
|
3
|
+
export default class MakeAnnotationNamespaceUnique {
|
|
4
|
+
transform({ json, uri }) {
|
|
5
|
+
const uniquePart = crc16(uri).toString(16);
|
|
6
|
+
// First add current schema as reference
|
|
7
|
+
const schema = MetadataJsonUtil.getSchemaNode(json);
|
|
8
|
+
const references = this.getReferences(json);
|
|
9
|
+
references.push(this.createReference(schema, uri));
|
|
10
|
+
// Then rename the namespace/alias
|
|
11
|
+
schema._attributes.Namespace += "." + uniquePart;
|
|
12
|
+
delete schema._attributes["Alias"];
|
|
13
|
+
return json;
|
|
14
|
+
}
|
|
15
|
+
createReference(schema, uri) {
|
|
16
|
+
const attributes = {
|
|
17
|
+
Namespace: schema._attributes.Namespace
|
|
18
|
+
};
|
|
19
|
+
if (schema._attributes.Alias) {
|
|
20
|
+
attributes.Alias = schema._attributes.Alias;
|
|
21
|
+
}
|
|
22
|
+
;
|
|
23
|
+
return {
|
|
24
|
+
_attributes: {
|
|
25
|
+
Uri: uri
|
|
26
|
+
},
|
|
27
|
+
"edmx:Include": {
|
|
28
|
+
_attributes: attributes
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
getReferences(json) {
|
|
33
|
+
const REFERENCE_NODE_NAME = "edmx:Reference";
|
|
34
|
+
const references = MetadataJsonUtil.getEdmx(json)[REFERENCE_NODE_NAME];
|
|
35
|
+
if (!Array.isArray(references)) {
|
|
36
|
+
MetadataJsonUtil.getEdmx(json)[REFERENCE_NODE_NAME] = [references];
|
|
37
|
+
}
|
|
38
|
+
return MetadataJsonUtil.getEdmx(json)[REFERENCE_NODE_NAME];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=makeAnnotationNamespaceUnique.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import MetadataJsonUtil from "../converter/metadataJsonUtil.js";
|
|
2
|
+
export default class RemoveAllSchemaNodesExceptAnnotations {
|
|
3
|
+
transform({ json }) {
|
|
4
|
+
const schema = MetadataJsonUtil.getSchemaNode(json);
|
|
5
|
+
for (const key of Object.keys(schema)) {
|
|
6
|
+
if (key !== "_attributes" && key !== "Annotations") {
|
|
7
|
+
delete schema[key];
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return json;
|
|
11
|
+
// TODO: remove also references not used in annotations
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=removeAllSchemaNodesExceptAnnotations.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import Language from "../../model/language.js";
|
|
2
|
+
import ServiceRequestor from "../serviceRequestor.js";
|
|
3
|
+
export interface TransformerInput {
|
|
4
|
+
uri: string;
|
|
5
|
+
json: any;
|
|
6
|
+
xml: string;
|
|
7
|
+
language: Language;
|
|
8
|
+
serviceRequestor: ServiceRequestor;
|
|
9
|
+
}
|
|
10
|
+
export default interface Transformer {
|
|
11
|
+
transform(input: TransformerInput): any;
|
|
12
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import Transformer, { TransformerInput } from "../transformers/transformer.js";
|
|
2
|
+
export default class TraverseReferences implements Transformer {
|
|
3
|
+
private metadataUrl?;
|
|
4
|
+
constructor(metadataUrl?: string);
|
|
5
|
+
transform({ json, language, serviceRequestor, uri: parentUrl }: TransformerInput): Promise<void>;
|
|
6
|
+
private shouldIgnoreUrl;
|
|
7
|
+
private mergeAnnotations;
|
|
8
|
+
private static isTraversable;
|
|
9
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import MetadataJsonUtil from "../converter/metadataJsonUtil.js";
|
|
2
|
+
import DataSourceODataAnnotation from "../dataSource/dataSourceODataAnnotation.js";
|
|
3
|
+
import UrlUtil from "../../util/urlUtil.js";
|
|
4
|
+
export default class TraverseReferences {
|
|
5
|
+
metadataUrl;
|
|
6
|
+
constructor(metadataUrl) {
|
|
7
|
+
this.metadataUrl = metadataUrl;
|
|
8
|
+
}
|
|
9
|
+
async transform({ json, language, serviceRequestor, uri: parentUrl }) {
|
|
10
|
+
const references = MetadataJsonUtil.getReferences(json).filter(TraverseReferences.isTraversable);
|
|
11
|
+
const promises = [];
|
|
12
|
+
for (const { includes, uri: relativeUrl } of references) {
|
|
13
|
+
const resourcePath = UrlUtil.getResourcePath(relativeUrl);
|
|
14
|
+
const absoluteUrl = UrlUtil.join(resourcePath, parentUrl);
|
|
15
|
+
if (this.shouldIgnoreUrl(absoluteUrl, [parentUrl, this.metadataUrl])) {
|
|
16
|
+
// If reference to metadata or its parent, don't traverse
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
const name = includes[0]?.namespace;
|
|
20
|
+
const dataSource = new DataSourceODataAnnotation(name, absoluteUrl, {}, this.metadataUrl);
|
|
21
|
+
promises.push(dataSource.downloadAnnotation(language, serviceRequestor)
|
|
22
|
+
.then(childAnnotation => ({ name, childAnnotation })));
|
|
23
|
+
}
|
|
24
|
+
const childAnnotations = await Promise.all(promises);
|
|
25
|
+
for (const { childAnnotation } of childAnnotations) {
|
|
26
|
+
this.mergeAnnotations(json, childAnnotation);
|
|
27
|
+
}
|
|
28
|
+
return json;
|
|
29
|
+
}
|
|
30
|
+
shouldIgnoreUrl(referenceUrl, urlsToIgnore) {
|
|
31
|
+
const toResourcePath = (url) => url && UrlUtil.getResourcePath(url);
|
|
32
|
+
const isEqual = (a, b) => a && b && a.toLowerCase() === b.toLowerCase();
|
|
33
|
+
return urlsToIgnore.map(toResourcePath).some(url => isEqual(referenceUrl, url));
|
|
34
|
+
}
|
|
35
|
+
mergeAnnotations(parentJson, nestedJson) {
|
|
36
|
+
const parentAnnotations = MetadataJsonUtil.getAnnotations(parentJson);
|
|
37
|
+
const parentMapByTarget = MetadataJsonUtil.mapAnnotationsPerTarget(parentJson);
|
|
38
|
+
const nestedMapByTarget = MetadataJsonUtil.mapAnnotationsPerTarget(nestedJson);
|
|
39
|
+
for (const nested of [...nestedMapByTarget].map(([target, { json }]) => ({ target, json }))) {
|
|
40
|
+
// If we found parent annotation with the same target - we extend it
|
|
41
|
+
// with missing <Annotation> nodes. If not, just add it to the end.
|
|
42
|
+
// Annotations do not have a merge logic If same target & term is in
|
|
43
|
+
// parent and nested, parent wins (same logic as UI5 in
|
|
44
|
+
// sap/ui/model/odata/v4/ODataMetaModel.js mergeAnnotations).
|
|
45
|
+
const parent = parentMapByTarget.get(nested.target);
|
|
46
|
+
if (parent) {
|
|
47
|
+
MetadataJsonUtil.toArrayTransform(parent.json, "Annotation");
|
|
48
|
+
const parentTerms = parent.json.Annotation.map((item) => item._attributes.Term);
|
|
49
|
+
for (const nestedAnnotation of MetadataJsonUtil.toArrayReadOnly(nested.json.Annotation)) {
|
|
50
|
+
if (!parentTerms.includes(nestedAnnotation._attributes.Term)) {
|
|
51
|
+
parent.json.Annotation.push(nestedAnnotation);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
parentAnnotations.push(nested.json);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
MetadataJsonUtil.setAnnotations(parentJson, parentAnnotations);
|
|
60
|
+
}
|
|
61
|
+
static isTraversable(reference) {
|
|
62
|
+
const IGNORED_NAMESPACES = ["com.sap.vocabularies.", "Org.OData."];
|
|
63
|
+
return !reference.includes.some(include => IGNORED_NAMESPACES.some(namespace => include.namespace.startsWith(namespace)));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=traverseReferences.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { IAppVariantInfo } from "./model/types.js";
|
|
2
|
+
export default class AppVariantManager {
|
|
3
|
+
static process(appVariantResources: any[], projectNamespace: string, taskUtil: any): Promise<IAppVariantInfo>;
|
|
4
|
+
static getAppVariantResourcesToProcess(workspace: any): Promise<any[]>;
|
|
5
|
+
static updateChanges(appVariantResources: any[], projectNamespace: string): Promise<void>;
|
|
6
|
+
private static isManifestChange;
|
|
7
|
+
private static isManifestAppVariant;
|
|
8
|
+
static getAppVariantInfo(appVariantResources: any[]): Promise<IAppVariantInfo>;
|
|
9
|
+
private static validateManifest;
|
|
10
|
+
private static updateRelativePaths;
|
|
11
|
+
private static omitFiles;
|
|
12
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import ResourceUtil from "./util/resourceUtil.js";
|
|
2
|
+
import { posix as path } from "path";
|
|
3
|
+
import { renameResources } from "./util/commonUtil.js";
|
|
4
|
+
const EXTENSIONS_TO_PROCESS = "js,json,xml,html,properties,change,appdescr_variant,ctrl_variant,ctrl_variant_change,ctrl_variant_management_change,variant,fioriversion,codeChange,xmlViewChange,context";
|
|
5
|
+
export default class AppVariantManager {
|
|
6
|
+
static async process(appVariantResources, projectNamespace, taskUtil) {
|
|
7
|
+
for (const resource of appVariantResources) {
|
|
8
|
+
this.omitFiles(resource, taskUtil);
|
|
9
|
+
}
|
|
10
|
+
await this.updateChanges(appVariantResources, projectNamespace);
|
|
11
|
+
return this.getAppVariantInfo(appVariantResources);
|
|
12
|
+
}
|
|
13
|
+
static getAppVariantResourcesToProcess(workspace) {
|
|
14
|
+
return workspace.byGlob(`/**/*.{${EXTENSIONS_TO_PROCESS}}`);
|
|
15
|
+
}
|
|
16
|
+
static async updateChanges(appVariantResources, projectNamespace) {
|
|
17
|
+
const changesFolder = ResourceUtil.getResourcePath(projectNamespace, "changes");
|
|
18
|
+
const changes = new Map();
|
|
19
|
+
const resourcesByPath = new Map();
|
|
20
|
+
let manifest;
|
|
21
|
+
for (const resource of appVariantResources) {
|
|
22
|
+
if (this.isManifestAppVariant(resource)) {
|
|
23
|
+
manifest = await ResourceUtil.getJson(resource);
|
|
24
|
+
}
|
|
25
|
+
const resourcePath = resource.getPath();
|
|
26
|
+
const basename = path.dirname(resourcePath);
|
|
27
|
+
if (basename.startsWith(changesFolder)) {
|
|
28
|
+
changes.set(resourcePath, await ResourceUtil.getString(resource));
|
|
29
|
+
resourcesByPath.set(resourcePath, resource);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
this.updateRelativePaths(changes, projectNamespace);
|
|
33
|
+
this.validateManifest(manifest);
|
|
34
|
+
const renamedChanges = renameResources(changes, manifest.reference, manifest.id);
|
|
35
|
+
renamedChanges.forEach((renamedContent, resourcePath) => {
|
|
36
|
+
const resource = resourcesByPath.get(resourcePath);
|
|
37
|
+
ResourceUtil.setString(resource, renamedContent);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
static isManifestChange(resource) {
|
|
41
|
+
const changesManifestFolder = path.join("changes", "manifest");
|
|
42
|
+
const resourcePath = typeof resource === "string" ? resource : resource.getPath();
|
|
43
|
+
const dirname = path.dirname(resourcePath);
|
|
44
|
+
return dirname.endsWith(changesManifestFolder);
|
|
45
|
+
}
|
|
46
|
+
static isManifestAppVariant(resource) {
|
|
47
|
+
const MANIFEST_APP_VARIANT = "manifest.appdescr_variant";
|
|
48
|
+
const basename = path.basename(resource.getPath());
|
|
49
|
+
return basename === MANIFEST_APP_VARIANT;
|
|
50
|
+
}
|
|
51
|
+
static async getAppVariantInfo(appVariantResources) {
|
|
52
|
+
let manifest;
|
|
53
|
+
const manifestChanges = [];
|
|
54
|
+
for (const resource of appVariantResources) {
|
|
55
|
+
if (this.isManifestAppVariant(resource)) {
|
|
56
|
+
manifest = await ResourceUtil.getJson(resource);
|
|
57
|
+
}
|
|
58
|
+
else if (this.isManifestChange(resource)) {
|
|
59
|
+
const content = await ResourceUtil.getString(resource);
|
|
60
|
+
manifestChanges.push(JSON.parse(content));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
this.validateManifest(manifest);
|
|
64
|
+
// Order is important: apply manifest.json changes first, then *.change
|
|
65
|
+
// files. UI5 does the same.
|
|
66
|
+
const changes = (manifest.content ?? []).concat(manifestChanges);
|
|
67
|
+
return {
|
|
68
|
+
id: manifest.id,
|
|
69
|
+
reference: manifest.reference,
|
|
70
|
+
layer: manifest.layer,
|
|
71
|
+
changes
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
static validateManifest(manifest) {
|
|
75
|
+
if (!manifest) {
|
|
76
|
+
throw new Error("Adaptation project should contain manifest.appdescr_variant");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// TODO In future this should be handled by merger which needs to know change and target location
|
|
80
|
+
static updateRelativePaths(changes, projectNamespace) {
|
|
81
|
+
changes.forEach((jsonString, resourcePath) => {
|
|
82
|
+
if (this.isManifestChange(resourcePath)) {
|
|
83
|
+
const change = JSON.parse(jsonString);
|
|
84
|
+
if (change.changeType === "appdescr_app_addAnnotationsToOData") {
|
|
85
|
+
for (const dataSource of Object.values(change.content.dataSource)) {
|
|
86
|
+
if (!dataSource.uri.startsWith("/")) {
|
|
87
|
+
const basepath = path.dirname(ResourceUtil.relativeToRoot(resourcePath, projectNamespace));
|
|
88
|
+
dataSource.uri = path.join(basepath.replace(/^\//, ""), dataSource.uri);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
changes.set(resourcePath, JSON.stringify(change));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
static omitFiles(resource, taskUtil) {
|
|
97
|
+
if (this.isManifestAppVariant(resource) || this.isManifestChange(resource)) {
|
|
98
|
+
taskUtil.setTag(resource, taskUtil.STANDARD_TAGS.OmitFromBuildResult, true);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=appVariantManager.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { IAppVariantInfo, IProjectOptions } from "./model/types.js";
|
|
2
|
+
import IProcessor from "./processors/processor.js";
|
|
3
|
+
export interface IBaseAppResources {
|
|
4
|
+
resources: any[];
|
|
5
|
+
manifestInfo: IManifestInfo;
|
|
6
|
+
}
|
|
7
|
+
export interface IManifestIdVersion {
|
|
8
|
+
id: string;
|
|
9
|
+
version: string;
|
|
10
|
+
}
|
|
11
|
+
export interface IManifestInfo extends IManifestIdVersion {
|
|
12
|
+
i18nPath: string;
|
|
13
|
+
}
|
|
14
|
+
export default class BaseAppManager {
|
|
15
|
+
static process(baseAppFiles: Map<string, string>, appVariantInfo: IAppVariantInfo, options: IProjectOptions, processor: IProcessor): Promise<IBaseAppResources>;
|
|
16
|
+
private static updateAdaptationProperties;
|
|
17
|
+
static getIdVersion(manifest: any): IManifestIdVersion;
|
|
18
|
+
static getManifestInfo(manifest: any): IManifestInfo;
|
|
19
|
+
private static extractI18nPathFromManifest;
|
|
20
|
+
private static extractI18NFromBundleName;
|
|
21
|
+
private static extractI18NFromBundleUrl;
|
|
22
|
+
private static getBaseAppManifest;
|
|
23
|
+
private static fillAppVariantIdHierarchy;
|
|
24
|
+
private static VALIDATION_RULES;
|
|
25
|
+
static validateProperty(value: string, property: string): void;
|
|
26
|
+
static applyDescriptorChanges(baseAppManifest: any, { layer, changes, id }: IAppVariantInfo): Promise<void>;
|
|
27
|
+
private static adjustAddNewModelEnhanceWith;
|
|
28
|
+
static writeToWorkspace(baseAppFiles: Map<string, string>, projectNamespace: string): any[];
|
|
29
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { Applier, Change, RegistrationBuild } from "../dist/bundle.js";
|
|
2
|
+
import { dotToUnderscore, removePropertiesExtension } from "./util/commonUtil.js";
|
|
3
|
+
import BuildStrategy from "./buildStrategy.js";
|
|
4
|
+
import ResourceUtil from "./util/resourceUtil.js";
|
|
5
|
+
import { getLogger } from "@ui5/logger";
|
|
6
|
+
import { renameResources } from "./util/commonUtil.js";
|
|
7
|
+
const log = getLogger("@ui5/task-adaptation::BaseAppManager");
|
|
8
|
+
export default class BaseAppManager {
|
|
9
|
+
static async process(baseAppFiles, appVariantInfo, options, processor) {
|
|
10
|
+
const baseAppManifest = this.getBaseAppManifest(baseAppFiles);
|
|
11
|
+
const { id, version } = this.getIdVersion(baseAppManifest.content);
|
|
12
|
+
this.validateProperty(id, "sap.app/id");
|
|
13
|
+
this.validateProperty(version, "sap.app/applicationVersion/version");
|
|
14
|
+
const renamedBaseAppFiles = renameResources(baseAppFiles, appVariantInfo.reference, appVariantInfo.id);
|
|
15
|
+
const { filepath, content } = this.getBaseAppManifest(renamedBaseAppFiles);
|
|
16
|
+
await processor.updateLandscapeSpecificContent(content, renamedBaseAppFiles);
|
|
17
|
+
this.fillAppVariantIdHierarchy(processor, id, version, content);
|
|
18
|
+
this.updateAdaptationProperties(content);
|
|
19
|
+
await this.applyDescriptorChanges(content, appVariantInfo);
|
|
20
|
+
renamedBaseAppFiles.set(filepath, JSON.stringify(content));
|
|
21
|
+
return {
|
|
22
|
+
resources: this.writeToWorkspace(renamedBaseAppFiles, options.projectNamespace),
|
|
23
|
+
manifestInfo: this.getManifestInfo(content)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
static updateAdaptationProperties(content) {
|
|
27
|
+
if (content["sap.fiori"]?.cloudDevAdaptationStatus) {
|
|
28
|
+
delete content["sap.fiori"].cloudDevAdaptationStatus;
|
|
29
|
+
}
|
|
30
|
+
if (content["sap.ui5"] == null) {
|
|
31
|
+
content["sap.ui5"] = {};
|
|
32
|
+
}
|
|
33
|
+
content["sap.ui5"].isCloudDevAdaptation = true;
|
|
34
|
+
}
|
|
35
|
+
static getIdVersion(manifest) {
|
|
36
|
+
const id = manifest["sap.app"]?.id;
|
|
37
|
+
const version = manifest["sap.app"]?.applicationVersion?.version;
|
|
38
|
+
return { id, version };
|
|
39
|
+
}
|
|
40
|
+
static getManifestInfo(manifest) {
|
|
41
|
+
const { id, version } = this.getIdVersion(manifest);
|
|
42
|
+
const i18nNode = manifest["sap.app"]?.i18n;
|
|
43
|
+
const i18nPath = this.extractI18nPathFromManifest(id, i18nNode);
|
|
44
|
+
return { id, version, i18nPath };
|
|
45
|
+
}
|
|
46
|
+
static extractI18nPathFromManifest(sapAppId, i18nNode) {
|
|
47
|
+
if (typeof i18nNode === "object") {
|
|
48
|
+
return i18nNode["bundleUrl"] ? this.extractI18NFromBundleUrl(i18nNode) : this.extractI18NFromBundleName(i18nNode, sapAppId);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
return `${sapAppId?.replaceAll(".", "/")}/${i18nNode}`;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
static extractI18NFromBundleName(i18nNode, sapAppId) {
|
|
55
|
+
return i18nNode["bundleName"].replace(sapAppId, "").replaceAll(".", "/").substring(1);
|
|
56
|
+
}
|
|
57
|
+
static extractI18NFromBundleUrl(i18nNode) {
|
|
58
|
+
return removePropertiesExtension(i18nNode["bundleUrl"]);
|
|
59
|
+
}
|
|
60
|
+
static getBaseAppManifest(baseAppFiles) {
|
|
61
|
+
const manifestContent = baseAppFiles.get("manifest.json");
|
|
62
|
+
if (manifestContent) {
|
|
63
|
+
return {
|
|
64
|
+
content: JSON.parse(manifestContent),
|
|
65
|
+
filepath: "manifest.json"
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
throw new Error("Original application should have manifest.json in root folder");
|
|
69
|
+
}
|
|
70
|
+
static fillAppVariantIdHierarchy(processor, id, version, baseAppManifest) {
|
|
71
|
+
log.verbose("Filling up app variant hierarchy in manifest.json");
|
|
72
|
+
if (baseAppManifest["sap.ui5"] == null) {
|
|
73
|
+
baseAppManifest["sap.ui5"] = {};
|
|
74
|
+
}
|
|
75
|
+
if (baseAppManifest["sap.ui5"].appVariantIdHierarchy == null) {
|
|
76
|
+
baseAppManifest["sap.ui5"].appVariantIdHierarchy = [];
|
|
77
|
+
}
|
|
78
|
+
const appVariantIdHierarchyItem = processor.createAppVariantHierarchyItem(id, version);
|
|
79
|
+
baseAppManifest["sap.ui5"].appVariantIdHierarchy.unshift(appVariantIdHierarchyItem);
|
|
80
|
+
}
|
|
81
|
+
static VALIDATION_RULES = new Map([["sap.app/id", (value) => {
|
|
82
|
+
if (!value.includes(".")) {
|
|
83
|
+
throw new Error(`The original application id '${value}' should consist of multiple segments split by dot, e.g.: original.id`);
|
|
84
|
+
}
|
|
85
|
+
}]]);
|
|
86
|
+
static validateProperty(value, property) {
|
|
87
|
+
if (!value) {
|
|
88
|
+
throw new Error(`Original application manifest should have ${property}`);
|
|
89
|
+
}
|
|
90
|
+
let validatationRule = this.VALIDATION_RULES.get(property);
|
|
91
|
+
if (validatationRule) {
|
|
92
|
+
validatationRule(value);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
static async applyDescriptorChanges(baseAppManifest, { layer, changes, id }) {
|
|
96
|
+
log.verbose("Applying appVariant changes");
|
|
97
|
+
const changesContent = new Array();
|
|
98
|
+
const i18nBundleName = dotToUnderscore(id);
|
|
99
|
+
for (const change of structuredClone(changes)) {
|
|
100
|
+
if (layer) {
|
|
101
|
+
change.layer = layer;
|
|
102
|
+
}
|
|
103
|
+
changesContent.push(new Change(change));
|
|
104
|
+
this.adjustAddNewModelEnhanceWith(change, i18nBundleName);
|
|
105
|
+
}
|
|
106
|
+
if (changesContent.length > 0) {
|
|
107
|
+
const strategy = new BuildStrategy(RegistrationBuild);
|
|
108
|
+
await Applier.applyChanges(baseAppManifest, changesContent, strategy);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
static adjustAddNewModelEnhanceWith(change, i18nBundleName) {
|
|
112
|
+
if (change.changeType === "appdescr_ui5_addNewModelEnhanceWith") {
|
|
113
|
+
if (change.texts == null) {
|
|
114
|
+
// We need to add texts properties to changes because not all
|
|
115
|
+
// have texts property. Changes without texts property can
|
|
116
|
+
// causes issues in bundle.js This is needed for now, and will
|
|
117
|
+
// be removed as soon as change merger in openUI5 is updated
|
|
118
|
+
change.texts = { i18n: change.content?.bundleUrl || "i18n/i18n.properties" };
|
|
119
|
+
}
|
|
120
|
+
change.texts.i18n = i18nBundleName + "/" + change.texts.i18n;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
static writeToWorkspace(baseAppFiles, projectNamespace) {
|
|
124
|
+
const IGNORE_FILES = [
|
|
125
|
+
"manifest-bundle.zip",
|
|
126
|
+
"Component-preload.js",
|
|
127
|
+
"sap-ui-cachebuster-info.json"
|
|
128
|
+
];
|
|
129
|
+
const resources = [];
|
|
130
|
+
for (let filename of baseAppFiles.keys()) {
|
|
131
|
+
if (!IGNORE_FILES.includes(filename)) {
|
|
132
|
+
const resource = ResourceUtil.createResource(filename, projectNamespace, baseAppFiles.get(filename));
|
|
133
|
+
resources.push(resource);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return resources;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=baseAppManager.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export default class BuildStrategy {
|
|
2
|
+
registrationBuild;
|
|
3
|
+
constructor(registrationBuild) {
|
|
4
|
+
this.registrationBuild = registrationBuild;
|
|
5
|
+
}
|
|
6
|
+
registry() {
|
|
7
|
+
return Promise.resolve(this.registrationBuild);
|
|
8
|
+
}
|
|
9
|
+
handleError(error) {
|
|
10
|
+
throw error;
|
|
11
|
+
}
|
|
12
|
+
processTexts(manifest) {
|
|
13
|
+
if (typeof manifest["sap.app"].i18n === "string") {
|
|
14
|
+
manifest["sap.app"].i18n = { bundleUrl: manifest["sap.app"].i18n };
|
|
15
|
+
}
|
|
16
|
+
return manifest;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=buildStrategy.js.map
|
package/dist/bundle.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare const RegistrationBuild: () => void;
|
|
2
|
+
|
|
3
|
+
export declare class Applier {
|
|
4
|
+
static applyChanges(manifest: any, changes: Change[], strategy: any): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export declare class Change {
|
|
8
|
+
constructor(change: any);
|
|
9
|
+
getLayer(): string;
|
|
10
|
+
_oDefinition: any;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export declare class V2MetadataConverter {
|
|
14
|
+
convertXMLMetadata(jsdom: any): any;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export declare class V4MetadataConverter {
|
|
18
|
+
convertXMLMetadata(jsdom: any): any;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export declare class URI {
|
|
22
|
+
constructor(relativeUrl: string);
|
|
23
|
+
absoluteTo(url: string): string;
|
|
24
|
+
static parse(url: string): { path: string };
|
|
25
|
+
}
|