@ui5/task-adaptation 1.6.6 → 1.6.8
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 +9 -1
- package/dist/adapters/abapAdapter.d.ts +2 -1
- package/dist/adapters/abapAdapter.js +3 -0
- package/dist/adapters/adapter.d.ts +2 -1
- package/dist/adapters/cfAdapter.d.ts +2 -1
- package/dist/adapters/cfAdapter.js +14 -0
- package/dist/adapters/commands/command.d.ts +7 -7
- package/dist/adapters/commands/command.js +3 -2
- package/dist/adapters/commands/downloadAnnotationsCommand.d.ts +1 -1
- package/dist/adapters/commands/downloadAnnotationsCommand.js +4 -3
- package/dist/adapters/commands/fetchPreviewResourcesCommand.js +4 -2
- package/dist/adapters/commands/filterFilesCommand.d.ts +1 -1
- package/dist/adapters/commands/filterFilesCommand.js +2 -1
- package/dist/adapters/commands/i18nPropertiesMergeCommand.d.ts +1 -1
- package/dist/adapters/commands/i18nPropertiesMergeCommand.js +9 -6
- package/dist/adapters/commands/omitDeletedResourcesCommand.d.ts +1 -1
- package/dist/adapters/commands/omitDeletedResourcesCommand.js +1 -1
- package/dist/adapters/commands/processPreviewResourcesCommand.d.ts +1 -1
- package/dist/adapters/commands/processPreviewResourcesCommand.js +14 -7
- package/dist/adapters/commands/renameFilesCommand.d.ts +10 -2
- package/dist/adapters/commands/renameFilesCommand.js +45 -17
- package/dist/adapters/commands/renameManifestCommand.d.ts +14 -0
- package/dist/adapters/commands/renameManifestCommand.js +32 -0
- package/dist/adapters/commands/writeResourcesCommand.d.ts +1 -1
- package/dist/adapters/commands/xsAppJsonEnhanceRoutesCommand.d.ts +1 -1
- package/dist/adapters/commands/xsAppJsonEnhanceRoutesCommand.js +4 -3
- package/dist/adapters/commands/xsAppJsonMergeCommand.d.ts +1 -1
- package/dist/adapters/commands/xsAppJsonMergeCommand.js +4 -3
- package/dist/adapters/previewAdapter.d.ts +2 -1
- package/dist/adapters/previewAdapter.js +3 -0
- package/dist/annotations/abapAnnotationManager.js +1 -1
- package/dist/annotations/dataSource/dataSourceManager.d.ts +2 -1
- package/dist/annotations/dataSource/dataSourceManager.js +16 -8
- package/dist/appVariant.d.ts +3 -3
- package/dist/appVariant.js +7 -7
- package/dist/baseApp.d.ts +3 -3
- package/dist/baseApp.js +4 -4
- package/dist/bundle.js +71 -34
- package/dist/cache/cacheHolder.d.ts +11 -2
- package/dist/cache/cacheHolder.js +23 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +24 -4
- package/dist/landscapeConfiguration.d.ts +3 -3
- package/dist/landscapeConfiguration.js +38 -28
- package/dist/model/types.d.ts +5 -1
- package/dist/repositories/abapProvider.js +2 -2
- package/dist/repositories/abapRepository.d.ts +1 -1
- package/dist/repositories/cacheRepository.d.ts +10 -0
- package/dist/repositories/cacheRepository.js +29 -0
- package/dist/repositories/html5Repository.d.ts +1 -1
- package/dist/repositories/localRepository.d.ts +1 -1
- package/dist/repositories/repository.d.ts +1 -1
- package/dist/util/cfUtil.d.ts +6 -24
- package/dist/util/cfUtil.js +36 -93
- package/dist/util/commonUtil.d.ts +6 -1
- package/dist/util/commonUtil.js +16 -1
- package/dist/util/fsUtil.d.ts +2 -2
- package/dist/util/fsUtil.js +4 -4
- package/dist/util/manifestUtil.d.ts +6 -0
- package/dist/util/manifestUtil.js +15 -0
- package/dist/util/movingHandler/changeFileMoveHandler.d.ts +3 -3
- package/dist/util/movingHandler/changeFileMoveHandler.js +5 -4
- package/dist/util/renamingHandlers/jsonRenamingHandler.d.ts +6 -5
- package/dist/util/renamingHandlers/jsonRenamingHandler.js +15 -15
- package/dist/util/renamingUtil.d.ts +17 -0
- package/dist/util/renamingUtil.js +102 -81
- package/dist/util/resourceUtil.d.ts +15 -6
- package/dist/util/resourceUtil.js +50 -14
- package/dist/util/validator/abapConnectionValidator.d.ts +5 -0
- package/dist/util/validator/abapConnectionValidator.js +22 -0
- package/dist/util/validator/abapValidator.d.ts +2 -4
- package/dist/util/validator/abapValidator.js +4 -16
- package/dist/util/zipUtil.d.ts +1 -1
- package/dist/util/zipUtil.js +1 -1
- package/package.json +14 -8
- package/types/ui5.d.ts +2 -0
- package/dist/util/renamingHandlers/renamingHandler.d.ts +0 -4
- package/dist/util/renamingHandlers/renamingHandler.js +0 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isManifestChange } from "../commonUtil.js";
|
|
1
|
+
import { bufferToString, isManifestChange } from "../commonUtil.js";
|
|
2
2
|
const EXT_DIR = "ext/";
|
|
3
3
|
const CHANGES_DIR = "changes/";
|
|
4
4
|
const nameSpaceRegex = new RegExp(`(?<=ControllerExtension.extend\\(")([^"]*)(?=")`);
|
|
@@ -21,7 +21,7 @@ function shouldMove(filename, content) {
|
|
|
21
21
|
* The namespace needs to be unique for clear identification
|
|
22
22
|
* If controller extension have the same namespace the last one will be used
|
|
23
23
|
* @param filename - The filename relative to the root
|
|
24
|
-
* @returns
|
|
24
|
+
* @returns `true` if the file's namespace should be renamed, `false` otherwise
|
|
25
25
|
*/
|
|
26
26
|
function shouldNamespaceRenamed(filename) {
|
|
27
27
|
return filename.startsWith(CHANGES_DIR) && filename.endsWith(".js");
|
|
@@ -38,7 +38,8 @@ function shouldNamespaceRenamed(filename) {
|
|
|
38
38
|
* the filename. Without 'changes' or 'ext' directory, we need to replace
|
|
39
39
|
* only rest: coding/FixingDay.js to app_var_id1/coding/FixingDay.js
|
|
40
40
|
* @param filename
|
|
41
|
-
* @returns
|
|
41
|
+
* @returns The path with the leading directory and all file extensions removed,
|
|
42
|
+
* e.g. `"changes/coding/FixingDay.js"` → `"coding/FixingDay"`
|
|
42
43
|
*/
|
|
43
44
|
function getPathWithoutExtensions(filename) {
|
|
44
45
|
const [_dir, ...rest] = filename.split("/");
|
|
@@ -66,7 +67,7 @@ export const moveFile = (filename, content, prefix, id) => {
|
|
|
66
67
|
renamingPath.set(restWOExtPath, [prefix, restWOExtPath].join("/"));
|
|
67
68
|
}
|
|
68
69
|
if (shouldNamespaceRenamed(filename)) {
|
|
69
|
-
const namespaceMatch = nameSpaceRegex.exec(content.trim());
|
|
70
|
+
const namespaceMatch = nameSpaceRegex.exec(bufferToString(content).trim());
|
|
70
71
|
const controllerExtensionPath = namespaceMatch ? namespaceMatch[0] : "";
|
|
71
72
|
const fileName = controllerExtensionPath.replace(id, "");
|
|
72
73
|
renamingPath.set(controllerExtensionPath, `${id}.${prefix}${fileName}`);
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
export default abstract class JsonRenamingHandler implements IRenamingHandler {
|
|
1
|
+
export default abstract class JsonRenamingHandler {
|
|
3
2
|
private original;
|
|
4
3
|
protected abstract filePath: string;
|
|
5
4
|
protected abstract jsonPathsToRestore: string[];
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
accept(filename: string): boolean;
|
|
6
|
+
before(json: any): void;
|
|
7
|
+
after(json: any): void;
|
|
8
|
+
snapshot(json: any): void;
|
|
9
|
+
restore(obj: any): void;
|
|
8
10
|
protected store(obj: any, path: string): void;
|
|
9
|
-
protected restore(obj: any): void;
|
|
10
11
|
private getByPath;
|
|
11
12
|
private setByPath;
|
|
12
13
|
}
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
export default class JsonRenamingHandler {
|
|
2
2
|
original = new Map();
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
if (content) {
|
|
6
|
-
const json = JSON.parse(content);
|
|
7
|
-
this.jsonPathsToRestore.forEach(path => this.store(json, path));
|
|
8
|
-
}
|
|
3
|
+
accept(filename) {
|
|
4
|
+
return filename.endsWith(this.filePath);
|
|
9
5
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (content) {
|
|
13
|
-
const json = JSON.parse(content);
|
|
14
|
-
this.restore(json);
|
|
15
|
-
files.set(this.filePath, JSON.stringify(json));
|
|
16
|
-
}
|
|
6
|
+
before(json) {
|
|
7
|
+
this.jsonPathsToRestore.forEach(path => this.store(json, path));
|
|
17
8
|
}
|
|
18
|
-
|
|
19
|
-
this.
|
|
9
|
+
after(json) {
|
|
10
|
+
this.restore(json);
|
|
11
|
+
}
|
|
12
|
+
snapshot(json) {
|
|
13
|
+
this.jsonPathsToRestore.forEach(path => this.store(json, path));
|
|
20
14
|
}
|
|
21
15
|
restore(obj) {
|
|
22
16
|
this.original.forEach((value, path) => this.setByPath(obj, value, path.split("/")));
|
|
23
17
|
}
|
|
18
|
+
store(obj, path) {
|
|
19
|
+
// Clone so the snapshot is decoupled from `obj`: when the same object is
|
|
20
|
+
// mutated in-place (JSON renaming), the stored value stays untouched.
|
|
21
|
+
const value = this.getByPath(obj, path.split("/"));
|
|
22
|
+
this.original.set(path, value === undefined ? undefined : structuredClone(value));
|
|
23
|
+
}
|
|
24
24
|
getByPath(obj, path) {
|
|
25
25
|
return path.reduce((o, p) => (o && o[p]) || undefined, obj);
|
|
26
26
|
}
|
|
@@ -1,3 +1,20 @@
|
|
|
1
1
|
export declare function rename(content: string, references: string[], replacement: string): string;
|
|
2
|
+
/**
|
|
3
|
+
* A precompiled renamer: the regex, replacement lookup and ignore set are built
|
|
4
|
+
* once and can be applied to many strings via `replace` without recompilation.
|
|
5
|
+
*/
|
|
6
|
+
export interface Renamer {
|
|
7
|
+
replace(content: string): string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Builds a reusable {@link Renamer} from the given references and ignore list.
|
|
11
|
+
* The expensive work (regex compilation, lookup construction) happens here once;
|
|
12
|
+
* the returned `replace` is a cheap single pass over each input string. Prefer
|
|
13
|
+
* this over calling {@link renameMap} repeatedly with the same references.
|
|
14
|
+
*
|
|
15
|
+
* Note: mutates `references` by dropping entries whose dot-count doesn't match.
|
|
16
|
+
*/
|
|
17
|
+
export declare function compileRenamer(references: Map<string, string>, ignoreInStrings: string[]): Renamer;
|
|
2
18
|
export declare function renameMap(content: string, references: Map<string, string>, ignoreInStrings: string[]): string;
|
|
19
|
+
export declare function renameJson(json: Record<string, unknown>, references: Map<string, string>, ignoreInStrings: string[]): void;
|
|
3
20
|
export declare function renameResources(files: ReadonlyMap<string, string>, search: string[], replacement: string): Map<string, string>;
|
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
import { getLogger } from "@ui5/logger";
|
|
2
2
|
const log = getLogger("@ui5/task-adaptation::RenamingUtil");
|
|
3
|
+
const dotToSlash = (string) => string.replaceAll(".", "/");
|
|
4
|
+
const escapeRegex = (string) => string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3
5
|
export function rename(content, references, replacement) {
|
|
4
6
|
return renameMap(content, new Map(references.map(ref => [ref, replacement])), [replacement]);
|
|
5
7
|
}
|
|
6
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Builds a reusable {@link Renamer} from the given references and ignore list.
|
|
10
|
+
* The expensive work (regex compilation, lookup construction) happens here once;
|
|
11
|
+
* the returned `replace` is a cheap single pass over each input string. Prefer
|
|
12
|
+
* this over calling {@link renameMap} repeatedly with the same references.
|
|
13
|
+
*
|
|
14
|
+
* Note: mutates `references` by dropping entries whose dot-count doesn't match.
|
|
15
|
+
*/
|
|
16
|
+
export function compileRenamer(references, ignoreInStrings) {
|
|
7
17
|
const ignoredReferenceKeys = [];
|
|
8
18
|
for (const [key, value] of references) {
|
|
9
19
|
if (value.includes(".") !== key.includes(".")) {
|
|
20
|
+
log.info(`Ignoring renaming of "${key}" → "${value}" because the dot count does not match.`);
|
|
10
21
|
ignoredReferenceKeys.push(key);
|
|
11
22
|
references.delete(key);
|
|
12
23
|
}
|
|
@@ -15,97 +26,107 @@ export function renameMap(content, references, ignoreInStrings) {
|
|
|
15
26
|
log.info(`Ignored renaming: ${ignoredReferenceKeys.join(", ")}`);
|
|
16
27
|
}
|
|
17
28
|
const searchTerms = [...references.keys()].filter(key => key.length > 0);
|
|
18
|
-
if (
|
|
19
|
-
return
|
|
29
|
+
if (searchTerms.length === 0) {
|
|
30
|
+
return {
|
|
31
|
+
replace: (content) => content
|
|
32
|
+
};
|
|
20
33
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return findAllOccurrences(content, string, start).map(i => ({ start: i, end: i + string.length }));
|
|
30
|
-
}).filter(arr => arr.length > 0) || [];
|
|
31
|
-
// We find the next search index with dots and slashes. Then we replace
|
|
32
|
-
// the nearest one and start search again in the next loop step.
|
|
33
|
-
const indices = new Array();
|
|
34
|
-
for (const searchTerm of searchTerms) {
|
|
35
|
-
const searchTermSlash = dotToSlash(searchTerm);
|
|
36
|
-
indices.push({
|
|
37
|
-
i: content.indexOf(searchTerm, start),
|
|
38
|
-
replacement: references.get(searchTerm),
|
|
39
|
-
searchTerm
|
|
40
|
-
}, {
|
|
41
|
-
i: content.indexOf(searchTermSlash, start),
|
|
42
|
-
replacement: dotToSlash(references.get(searchTerm)),
|
|
43
|
-
searchTerm: searchTermSlash
|
|
44
|
-
});
|
|
34
|
+
// Build replacement lookup: pattern → replacement string (both dot and slash variants).
|
|
35
|
+
const replacementMap = new Map();
|
|
36
|
+
for (const term of searchTerms) {
|
|
37
|
+
const replacement = references.get(term);
|
|
38
|
+
replacementMap.set(term, replacement);
|
|
39
|
+
const slashTerm = dotToSlash(term);
|
|
40
|
+
if (slashTerm !== term) {
|
|
41
|
+
replacementMap.set(slashTerm, dotToSlash(replacement));
|
|
45
42
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
}
|
|
44
|
+
// Build deduplicated ignore set with slash variants
|
|
45
|
+
const ignoreSet = new Set();
|
|
46
|
+
for (const ignoredString of ignoreInStrings) {
|
|
47
|
+
if (ignoredString) {
|
|
48
|
+
ignoreSet.add(ignoredString);
|
|
49
|
+
ignoreSet.add(dotToSlash(ignoredString));
|
|
49
50
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
}
|
|
52
|
+
// When a string appears in both replacementMap and ignoreSet, ignoreSet
|
|
53
|
+
// takes precedence — the match is skipped rather than replaced. Remove such
|
|
54
|
+
// keys from replacementMap so the intent is explicit instead of relying on
|
|
55
|
+
// runtime check order.
|
|
56
|
+
for (const ignored of ignoreSet) {
|
|
57
|
+
replacementMap.delete(ignored);
|
|
58
|
+
}
|
|
59
|
+
// Collect all unique patterns sorted by length descending (longest match first).
|
|
60
|
+
// V8 compiles alternation of literal strings into an Aho-Corasick automaton
|
|
61
|
+
// internally, giving us O(n + P + z) single-pass matching in native C++ code.
|
|
62
|
+
const allPatterns = new Set([...replacementMap.keys(), ...ignoreSet]);
|
|
63
|
+
const sorted = [...allPatterns].sort((a, b) => b.length - a.length);
|
|
64
|
+
// Reused across `replace` calls; `lastIndex` is reset at the start of each run.
|
|
65
|
+
const regex = new RegExp(sorted.map(escapeRegex).join("|"), "g");
|
|
66
|
+
return {
|
|
67
|
+
replace(content) {
|
|
68
|
+
if (!content) {
|
|
69
|
+
return content;
|
|
57
70
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
regex.lastIndex = 0;
|
|
72
|
+
// Single-pass: find all matches, skip ignored ones, batch-replace the rest
|
|
73
|
+
const parts = [];
|
|
74
|
+
let lastEnd = 0;
|
|
75
|
+
let match;
|
|
76
|
+
while ((match = regex.exec(content)) !== null) {
|
|
77
|
+
const matched = match[0];
|
|
78
|
+
if (ignoreSet.has(matched)) {
|
|
79
|
+
// ignore takes priority over replacement
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const replacement = replacementMap.get(matched);
|
|
83
|
+
if (replacement !== undefined) {
|
|
84
|
+
parts.push(content.substring(lastEnd, match.index));
|
|
85
|
+
parts.push(replacement);
|
|
86
|
+
lastEnd = match.index + matched.length;
|
|
70
87
|
}
|
|
71
88
|
}
|
|
72
|
-
return
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// substrings and the index could be the nearest, but after that the
|
|
79
|
-
// next index might be the actual find to replace, so we first of all
|
|
80
|
-
// ignore all the ignored substring findings and get the next actual
|
|
81
|
-
// replacement. But if there are only ignored substrings found, we take
|
|
82
|
-
// the first one just to skip it and go further.
|
|
83
|
-
const currentReplace = findCurrentReplace(found);
|
|
84
|
-
if (currentReplace.inBetween) {
|
|
85
|
-
start = currentReplace.inBetween.end;
|
|
89
|
+
// Nothing matched: return the original string without allocating a join.
|
|
90
|
+
if (lastEnd === 0) {
|
|
91
|
+
return content;
|
|
92
|
+
}
|
|
93
|
+
parts.push(content.substring(lastEnd));
|
|
94
|
+
return parts.join("");
|
|
86
95
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export function renameMap(content, references, ignoreInStrings) {
|
|
99
|
+
return compileRenamer(references, ignoreInStrings).replace(content);
|
|
100
|
+
}
|
|
101
|
+
export function renameJson(json, references, ignoreInStrings) {
|
|
102
|
+
const renamer = compileRenamer(references, ignoreInStrings);
|
|
103
|
+
function processObject(obj) {
|
|
104
|
+
for (const key of Object.keys(obj)) {
|
|
105
|
+
const renamedKey = renamer.replace(key);
|
|
106
|
+
const value = obj[key];
|
|
107
|
+
if (renamedKey !== key) {
|
|
108
|
+
obj[renamedKey] = value;
|
|
109
|
+
delete obj[key];
|
|
110
|
+
}
|
|
111
|
+
processValue(obj, renamedKey);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function processValue(container, index) {
|
|
115
|
+
const target = container;
|
|
116
|
+
const value = target[index];
|
|
117
|
+
if (typeof value === "string") {
|
|
118
|
+
target[index] = renamer.replace(value);
|
|
119
|
+
}
|
|
120
|
+
else if (Array.isArray(value)) {
|
|
121
|
+
value.forEach((_, i) => processValue(value, i));
|
|
122
|
+
}
|
|
123
|
+
else if (value !== null && typeof value === "object") {
|
|
124
|
+
processObject(value);
|
|
92
125
|
}
|
|
93
126
|
}
|
|
127
|
+
processObject(json);
|
|
94
128
|
}
|
|
95
129
|
export function renameResources(files, search, replacement) {
|
|
96
130
|
return new Map([...files].map(([filepath, content]) => [filepath, rename(content, search, replacement)]));
|
|
97
131
|
}
|
|
98
|
-
function findAllOccurrences(string, substring, start) {
|
|
99
|
-
if (!substring) {
|
|
100
|
-
return [];
|
|
101
|
-
}
|
|
102
|
-
const indices = [];
|
|
103
|
-
let index = start;
|
|
104
|
-
while ((index = string.indexOf(substring, index)) !== -1) {
|
|
105
|
-
indices.push(index);
|
|
106
|
-
index += substring.length; // shift from current finding
|
|
107
|
-
}
|
|
108
|
-
return indices;
|
|
109
|
-
}
|
|
110
|
-
;
|
|
111
132
|
//# sourceMappingURL=renamingUtil.js.map
|
|
@@ -1,14 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extensions of files whose contents are processed by the adaptation
|
|
3
|
+
* pipeline as text. Anything outside this whitelist is treated as binary
|
|
4
|
+
* (e.g. images, fonts) and is saved to the workspace verbatim by WorkspaceManager.
|
|
5
|
+
*
|
|
6
|
+
* Kept in sync with EXTENSIONS_TO_PROCESS in appVariant.ts.
|
|
7
|
+
*/
|
|
8
|
+
export declare const TEXT_EXTENSIONS: ReadonlySet<string>;
|
|
1
9
|
export default class ResourceUtil {
|
|
2
10
|
static getRootFolder(projectNamespace?: string): string;
|
|
3
11
|
static relativeToRoot(resourcePath: string, projectNamespace?: string): string;
|
|
4
12
|
static getResourcePath(projectNamespace?: string, ...paths: string[]): string;
|
|
5
|
-
static write(dir: string, files: Map<string,
|
|
6
|
-
static writeInProject(dir: string, files: Map<string,
|
|
7
|
-
static byGlob(dir: string, pattern: string, excludes?: string[]): Promise<Map<string,
|
|
8
|
-
static byGlobInProject(pattern: string, excludes?: string[]): Promise<Map<string,
|
|
13
|
+
static write(dir: string, files: Map<string, Buffer>): Promise<void[]>;
|
|
14
|
+
static writeInProject(dir: string, files: Map<string, Buffer>): Promise<void[]>;
|
|
15
|
+
static byGlob(dir: string, pattern: string, excludes?: string[]): Promise<Map<string, Buffer>>;
|
|
16
|
+
static byGlobInProject(pattern: string, excludes?: string[]): Promise<Map<string, Buffer>>;
|
|
9
17
|
static getString(resource: any): Promise<string>;
|
|
10
18
|
static getJson(resource: any): Promise<any>;
|
|
11
19
|
static setString(resource: any, str: string): void;
|
|
12
|
-
static createResource(filename: string, projectNamespace: string, content: string): any;
|
|
13
|
-
static
|
|
20
|
+
static createResource(filename: string, projectNamespace: string, content: string | Buffer): any;
|
|
21
|
+
private static createResourceFromContent;
|
|
22
|
+
static toFileMap(resources: ReadonlyArray<Resource>, projectNamespace?: string): Promise<Map<string, Buffer>>;
|
|
14
23
|
}
|
|
@@ -1,6 +1,31 @@
|
|
|
1
1
|
import * as resourceFactory from "@ui5/fs/resourceFactory";
|
|
2
2
|
import { posix as path } from "path";
|
|
3
3
|
const UTF8 = "utf8";
|
|
4
|
+
/**
|
|
5
|
+
* Extensions of files whose contents are processed by the adaptation
|
|
6
|
+
* pipeline as text. Anything outside this whitelist is treated as binary
|
|
7
|
+
* (e.g. images, fonts) and is saved to the workspace verbatim by WorkspaceManager.
|
|
8
|
+
*
|
|
9
|
+
* Kept in sync with EXTENSIONS_TO_PROCESS in appVariant.ts.
|
|
10
|
+
*/
|
|
11
|
+
export const TEXT_EXTENSIONS = new Set([
|
|
12
|
+
"js",
|
|
13
|
+
"json",
|
|
14
|
+
"xml",
|
|
15
|
+
"html",
|
|
16
|
+
"properties",
|
|
17
|
+
"change",
|
|
18
|
+
"appdescr_variant",
|
|
19
|
+
"ctrl_variant",
|
|
20
|
+
"ctrl_variant_change",
|
|
21
|
+
"ctrl_variant_management_change",
|
|
22
|
+
"annotation_change",
|
|
23
|
+
"variant",
|
|
24
|
+
"fioriversion",
|
|
25
|
+
"codeChange",
|
|
26
|
+
"xmlViewChange",
|
|
27
|
+
"context",
|
|
28
|
+
]);
|
|
4
29
|
export default class ResourceUtil {
|
|
5
30
|
static getRootFolder(projectNamespace) {
|
|
6
31
|
const newPath = ["/resources"];
|
|
@@ -21,7 +46,7 @@ export default class ResourceUtil {
|
|
|
21
46
|
* NOTE: to write in project folder (folder where 'webapp',
|
|
22
47
|
* 'package.json', 'ui5.yaml' located), use writeInProject method.
|
|
23
48
|
* @param dir The directory to write files to.
|
|
24
|
-
* @param files A Map of file paths and their contents.
|
|
49
|
+
* @param files A Map of file paths and their contents as Buffer.
|
|
25
50
|
* @returns A promise that resolves when all files have been written.
|
|
26
51
|
*/
|
|
27
52
|
static write(dir, files) {
|
|
@@ -30,8 +55,8 @@ export default class ResourceUtil {
|
|
|
30
55
|
virBasePath: "/"
|
|
31
56
|
});
|
|
32
57
|
const promises = [];
|
|
33
|
-
files.forEach((
|
|
34
|
-
const resource =
|
|
58
|
+
files.forEach((content, filename) => {
|
|
59
|
+
const resource = ResourceUtil.createResourceFromContent("/" + filename, content);
|
|
35
60
|
promises.push(fsTarget.write(resource));
|
|
36
61
|
});
|
|
37
62
|
return Promise.all(promises);
|
|
@@ -40,7 +65,7 @@ export default class ResourceUtil {
|
|
|
40
65
|
* Write files to the project folder (folder where 'webapp',
|
|
41
66
|
* 'package.json', 'ui5.yaml' located), use writeInProject method.
|
|
42
67
|
* @param dir The directory to write files to.
|
|
43
|
-
* @param files A Map of file paths and their contents.
|
|
68
|
+
* @param files A Map of file paths and their contents as Buffer.
|
|
44
69
|
* @returns A promise that resolves when all files have been written.
|
|
45
70
|
*/
|
|
46
71
|
static writeInProject(dir, files) {
|
|
@@ -53,22 +78,27 @@ export default class ResourceUtil {
|
|
|
53
78
|
* @param dir The directory to search in.
|
|
54
79
|
* @param pattern The glob pattern to match files, e.g., "/ui5AppInfo.json".
|
|
55
80
|
* @param excludes An array of glob patterns to exclude from the search.
|
|
56
|
-
* @returns A promise that resolves to a Map of file paths and their contents.
|
|
81
|
+
* @returns A promise that resolves to a Map of file paths and their contents as Buffer.
|
|
57
82
|
*/
|
|
58
|
-
static byGlob(dir, pattern, excludes = []) {
|
|
83
|
+
static async byGlob(dir, pattern, excludes = []) {
|
|
59
84
|
const adapter = resourceFactory.createAdapter({
|
|
60
85
|
fsBasePath: dir,
|
|
61
86
|
virBasePath: "/",
|
|
62
87
|
excludes
|
|
63
88
|
});
|
|
64
|
-
|
|
89
|
+
const resources = await adapter.byGlob(pattern);
|
|
90
|
+
const files = new Map();
|
|
91
|
+
for (const resource of resources) {
|
|
92
|
+
files.set(resource.getPath().substring(1), await resource.getBuffer());
|
|
93
|
+
}
|
|
94
|
+
return files;
|
|
65
95
|
}
|
|
66
96
|
/*
|
|
67
97
|
* Search files in the adaptation project (folder where 'webapp',
|
|
68
98
|
* 'package.json', 'ui5.yaml' located), excluding specified glob patterns.
|
|
69
99
|
* @param pattern The glob pattern to match files, e.g., "/ui5AppInfo.json".
|
|
70
100
|
* @param excludes An array of glob patterns to exclude from the search.
|
|
71
|
-
* @returns A promise that resolves to a Map of file paths and their contents.
|
|
101
|
+
* @returns A promise that resolves to a Map of file paths and their contents as Buffer.
|
|
72
102
|
*/
|
|
73
103
|
static byGlobInProject(pattern, excludes = []) {
|
|
74
104
|
return ResourceUtil.byGlob("./", pattern, [
|
|
@@ -87,16 +117,22 @@ export default class ResourceUtil {
|
|
|
87
117
|
resource.setBuffer(Buffer.from(str, UTF8));
|
|
88
118
|
}
|
|
89
119
|
static createResource(filename, projectNamespace, content) {
|
|
90
|
-
return
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
120
|
+
return ResourceUtil.createResourceFromContent(this.getResourcePath(projectNamespace, filename), content);
|
|
121
|
+
}
|
|
122
|
+
static createResourceFromContent(resourcePath, content) {
|
|
123
|
+
return resourceFactory.createResource(Buffer.isBuffer(content)
|
|
124
|
+
? { path: resourcePath, buffer: content }
|
|
125
|
+
: { path: resourcePath, string: content });
|
|
94
126
|
}
|
|
95
127
|
static async toFileMap(resources, projectNamespace) {
|
|
96
128
|
const files = new Map();
|
|
97
|
-
const
|
|
129
|
+
const rootFolder = projectNamespace ? ResourceUtil.getRootFolder(projectNamespace) : undefined;
|
|
98
130
|
for (const resource of resources) {
|
|
99
|
-
|
|
131
|
+
const resourcePath = resource.getPath();
|
|
132
|
+
const filename = rootFolder && resourcePath.startsWith(rootFolder)
|
|
133
|
+
? resourcePath.substring(rootFolder.length + 1)
|
|
134
|
+
: resourcePath.substring(1);
|
|
135
|
+
files.set(filename, await resource.getBuffer());
|
|
100
136
|
}
|
|
101
137
|
return files;
|
|
102
138
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { AbapTarget } from "@sap-ux/system-access";
|
|
2
|
+
import { IAbapTargetMeta } from "../../model/configuration.js";
|
|
3
|
+
export default class AbapConnectionValidator {
|
|
4
|
+
validateAndGetAbapTarget(target: AbapTarget & IAbapTargetMeta | undefined, destination: string | undefined): AbapTarget & IAbapTargetMeta;
|
|
5
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { validateObject } from "../commonUtil.js";
|
|
2
|
+
import { isAppStudio } from "@sap-ux/btp-utils";
|
|
3
|
+
import { getLogger } from "@ui5/logger";
|
|
4
|
+
const log = getLogger("@ui5/task-adaptation::AbapConnectionValidator");
|
|
5
|
+
export default class AbapConnectionValidator {
|
|
6
|
+
validateAndGetAbapTarget(target, destination) {
|
|
7
|
+
if (target) {
|
|
8
|
+
// if target configuration appears, we validate that it should be
|
|
9
|
+
// either target/destination for BAS or target/url for IDE we're
|
|
10
|
+
// trying to detect is it destination for BAS or url for IDE
|
|
11
|
+
const abapTargetProperties = isAppStudio() ? ["destination"] : ["url"];
|
|
12
|
+
validateObject(target, abapTargetProperties, "should be specified in ui5.yaml configuration/target");
|
|
13
|
+
return target;
|
|
14
|
+
}
|
|
15
|
+
else if (destination) {
|
|
16
|
+
log.warn("Destination is deprecated, use target/destination configuration instead");
|
|
17
|
+
return { destination };
|
|
18
|
+
}
|
|
19
|
+
throw new Error("Target should be specified in ui5.yaml configuration to connect the ABAP system");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=abapConnectionValidator.js.map
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { IAbapTargetMeta, IConfiguration, LandscapeType } from "../../model/configuration.js";
|
|
1
|
+
import { IConfiguration, LandscapeType } from "../../model/configuration.js";
|
|
3
2
|
import IValidator from "./validator.js";
|
|
4
3
|
export default class AbapValidator implements IValidator {
|
|
5
4
|
type: LandscapeType;
|
|
6
|
-
|
|
7
|
-
validateConfiguration({ target, destination }: IConfiguration): void;
|
|
5
|
+
validateConfiguration({ destination, target }: IConfiguration): void;
|
|
8
6
|
}
|
|
@@ -1,26 +1,14 @@
|
|
|
1
|
-
import { validateObject } from "../commonUtil.js";
|
|
2
|
-
import { isAppStudio } from "@sap-ux/btp-utils";
|
|
3
1
|
import { getLogger } from "@ui5/logger";
|
|
4
2
|
const log = getLogger("@ui5/task-adaptation::AbapValidator");
|
|
5
3
|
export default class AbapValidator {
|
|
6
4
|
type = "abap";
|
|
7
|
-
|
|
8
|
-
if (target) {
|
|
9
|
-
|
|
10
|
-
// either target/destination for BAS or target/url for IDE we're
|
|
11
|
-
// trying to detect is it destination for BAS or url for IDE
|
|
12
|
-
const abapTargetProperties = isAppStudio() ? ["destination"] : ["url"];
|
|
13
|
-
validateObject(target, abapTargetProperties, "should be specified in ui5.yaml configuration/target");
|
|
14
|
-
return target;
|
|
5
|
+
validateConfiguration({ destination, target }) {
|
|
6
|
+
if (!destination && !target) {
|
|
7
|
+
throw new Error("'target' should be specified in ui5.yaml configuration");
|
|
15
8
|
}
|
|
16
|
-
else if (destination) {
|
|
9
|
+
else if (destination && !target) {
|
|
17
10
|
log.warn("Destination is deprecated, use target/destination configuration instead");
|
|
18
|
-
return { destination };
|
|
19
11
|
}
|
|
20
|
-
throw new Error("Target should be specified in ui5.yaml configuration to connect the ABAP system");
|
|
21
|
-
}
|
|
22
|
-
validateConfiguration({ target, destination }) {
|
|
23
|
-
this.validateAndGetAbapTarget(target, destination);
|
|
24
12
|
}
|
|
25
13
|
}
|
|
26
14
|
//# sourceMappingURL=abapValidator.js.map
|
package/dist/util/zipUtil.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function unzipZipEntries(zip: Buffer): Promise<Map<string,
|
|
1
|
+
export declare function unzipZipEntries(zip: Buffer): Promise<Map<string, Buffer>>;
|
package/dist/util/zipUtil.js
CHANGED
|
@@ -11,6 +11,6 @@ export async function unzipZipEntries(zip) {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
function mapEntries(entries) {
|
|
14
|
-
return new Map(entries.filter(entry => !entry.isDirectory).map(entry => [entry.entryName, entry.getData()
|
|
14
|
+
return new Map(entries.filter(entry => !entry.isDirectory).map(entry => [entry.entryName, entry.getData()]));
|
|
15
15
|
}
|
|
16
16
|
//# sourceMappingURL=zipUtil.js.map
|
package/package.json
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ui5/task-adaptation",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.8",
|
|
4
4
|
"description": "Custom task for ui5-builder which allows building UI5 Flexibility Adaptation Projects for SAP BTP, Cloud Foundry environment",
|
|
5
|
-
"main": "index.js",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
6
12
|
"scripts": {
|
|
7
13
|
"test": "npm run lint && npm run build && npm run coverage",
|
|
8
14
|
"lint": "eslint ./src ./test/lib",
|
|
@@ -32,15 +38,15 @@
|
|
|
32
38
|
"author": "SAP SE",
|
|
33
39
|
"license": "Apache-2.0",
|
|
34
40
|
"dependencies": {
|
|
35
|
-
"@sap-ux/axios-extension": "^2.0.
|
|
36
|
-
"@sap-ux/btp-utils": "^2.0.
|
|
37
|
-
"@sap-ux/store": "^2.0.
|
|
38
|
-
"@sap-ux/system-access": "^1.0.
|
|
41
|
+
"@sap-ux/axios-extension": "^2.0.8",
|
|
42
|
+
"@sap-ux/btp-utils": "^2.0.6",
|
|
43
|
+
"@sap-ux/store": "^2.0.6",
|
|
44
|
+
"@sap-ux/system-access": "^1.0.10",
|
|
39
45
|
"@sap/cf-tools": "^3.2.2",
|
|
40
46
|
"@ui5/fs": "^4.0.1",
|
|
41
47
|
"@ui5/logger": "^4.0.1",
|
|
42
|
-
"adm-zip": "^0.
|
|
43
|
-
"axios": "^1.
|
|
48
|
+
"adm-zip": "^0.6.0",
|
|
49
|
+
"axios": "^1.18.1",
|
|
44
50
|
"crc": "^4.3.2",
|
|
45
51
|
"dotenv": "^16.0.3",
|
|
46
52
|
"filenamify": "^6.0.0",
|
package/types/ui5.d.ts
CHANGED