@ui5/task-adaptation 1.6.8 → 1.7.0

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.
Files changed (71) hide show
  1. package/.github/workflows/codeql.yml +35 -0
  2. package/.github/workflows/release-please.yml +53 -0
  3. package/.release-please-manifest.json +3 -0
  4. package/CHANGELOG.md +41 -39
  5. package/dist/adapters/abapAdapter.d.ts +3 -3
  6. package/dist/adapters/abapAdapter.js +19 -8
  7. package/dist/adapters/adapter.d.ts +3 -2
  8. package/dist/adapters/adapter.js +9 -3
  9. package/dist/adapters/cfAdapter.d.ts +2 -2
  10. package/dist/adapters/cfAdapter.js +12 -12
  11. package/dist/adapters/commands/command.js +0 -27
  12. package/dist/adapters/commands/downloadAnnotationsCommand.d.ts +3 -4
  13. package/dist/adapters/commands/downloadAnnotationsCommand.js +4 -4
  14. package/dist/adapters/commands/fetchPreviewResourcesCommand.js +1 -1
  15. package/dist/adapters/commands/omitDeletedResourcesCommand.d.ts +1 -1
  16. package/dist/adapters/commands/renameFilesCommand.d.ts +0 -22
  17. package/dist/adapters/commands/renameFilesCommand.js +2 -114
  18. package/dist/adapters/commands/renameManifestCommand.js +2 -2
  19. package/dist/adapters/previewAdapter.d.ts +2 -2
  20. package/dist/adapters/previewAdapter.js +4 -4
  21. package/dist/annotations/abapAnnotationManager.js +1 -3
  22. package/dist/annotations/dataSource/dataSource.d.ts +6 -5
  23. package/dist/annotations/dataSource/dataSource.js +36 -12
  24. package/dist/annotations/dataSource/dataSourceManager.d.ts +2 -2
  25. package/dist/annotations/dataSource/dataSourceManager.js +2 -2
  26. package/dist/annotations/dataSource/dataSourceOData.d.ts +2 -2
  27. package/dist/annotations/transformers/transformer.d.ts +2 -2
  28. package/dist/annotations/transformers/traverseReferences.d.ts +1 -1
  29. package/dist/annotations/transformers/traverseReferences.js +2 -2
  30. package/dist/appVariant.d.ts +5 -6
  31. package/dist/appVariant.js +9 -16
  32. package/dist/baseApp.d.ts +1 -0
  33. package/dist/baseApp.js +10 -0
  34. package/dist/bundle.js +39 -27
  35. package/dist/cache/cacheHolder.d.ts +6 -12
  36. package/dist/cache/cacheHolder.js +27 -39
  37. package/dist/cache/cachedResource.d.ts +2 -1
  38. package/dist/index.d.ts +5 -6
  39. package/dist/index.js +47 -40
  40. package/dist/landscapeConfiguration.d.ts +4 -4
  41. package/dist/landscapeConfiguration.js +48 -44
  42. package/dist/model/configuration.d.ts +0 -1
  43. package/dist/model/types.d.ts +0 -3
  44. package/dist/repositories/abapRepository.d.ts +1 -1
  45. package/dist/repositories/abapRepository.js +3 -3
  46. package/dist/repositories/cacheRepository.d.ts +4 -5
  47. package/dist/repositories/cacheRepository.js +10 -18
  48. package/dist/repositories/html5Repository.d.ts +1 -1
  49. package/dist/repositories/html5Repository.js +2 -2
  50. package/dist/repositories/localRepository.d.ts +1 -1
  51. package/dist/repositories/localRepository.js +2 -2
  52. package/dist/repositories/repository.d.ts +1 -1
  53. package/dist/util/commonUtil.d.ts +1 -9
  54. package/dist/util/commonUtil.js +27 -29
  55. package/dist/util/fsUtil.js +1 -2
  56. package/dist/util/movingHandler/changeFileMoveHandler.d.ts +1 -0
  57. package/dist/util/movingHandler/changeFileMoveHandler.js +11 -3
  58. package/dist/util/referencesBuilder.d.ts +15 -0
  59. package/dist/util/referencesBuilder.js +35 -0
  60. package/dist/util/renaming/fileRenamer.d.ts +23 -0
  61. package/dist/util/renaming/fileRenamer.js +120 -0
  62. package/dist/util/{renamingHandlers → renaming/handlers}/jsonRenamingHandler.d.ts +0 -2
  63. package/dist/util/{renamingHandlers → renaming/handlers}/jsonRenamingHandler.js +0 -6
  64. package/dist/util/{renamingUtil.d.ts → renaming/referenceRenaming.d.ts} +4 -4
  65. package/dist/util/{renamingUtil.js → renaming/referenceRenaming.js} +8 -8
  66. package/package.json +4 -3
  67. package/release-please-config.json +66 -0
  68. package/dist/annotations/serviceRequestor.d.ts +0 -9
  69. package/dist/annotations/serviceRequestor.js +0 -62
  70. /package/dist/util/{renamingHandlers → renaming/handlers}/manifestRenamingHandler.d.ts +0 -0
  71. /package/dist/util/{renamingHandlers → renaming/handlers}/manifestRenamingHandler.js +0 -0
package/dist/bundle.js CHANGED
@@ -4342,8 +4342,9 @@ _KeyPredicateParser.prototype.parse = function (sKeyPredicate) {
4342
4342
  this.finish();
4343
4343
  return oKeyProperties;
4344
4344
  };
4345
- function _SystemQueryOptionParser() {
4345
+ function _SystemQueryOptionParser(bParseFilter) {
4346
4346
  _Parser.apply(this, arguments);
4347
+ this.oFilterParser = bParseFilter ? new _FilterParser() : undefined;
4347
4348
  }
4348
4349
  _SystemQueryOptionParser.prototype = Object.create(_Parser.prototype);
4349
4350
  _SystemQueryOptionParser.prototype.parse = function (sOption) {
@@ -4429,10 +4430,17 @@ _SystemQueryOptionParser.prototype.parseSelect = function () {
4429
4430
  };
4430
4431
  };
4431
4432
  _SystemQueryOptionParser.prototype.parseSystemQueryOption = function () {
4432
- var oToken = this.advance("OPTION");
4433
+ const oToken = this.advance("OPTION");
4433
4434
  switch (oToken.value) {
4434
4435
  case "$expand":
4435
4436
  return this.parseExpand();
4437
+ case "$filter":
4438
+ {
4439
+ const oRaw = this.parseAnythingWithBrackets(oToken);
4440
+ return this.oFilterParser ? {
4441
+ $filter: this.oFilterParser.parse(oRaw.$filter)
4442
+ } : oRaw;
4443
+ }
4436
4444
  case "$select":
4437
4445
  return this.parseSelect();
4438
4446
  default:
@@ -4567,8 +4575,8 @@ var _Parser$1 = {
4567
4575
  parseKeyPredicate: function (sKeyPredicate) {
4568
4576
  return new _KeyPredicateParser().parse(sKeyPredicate);
4569
4577
  },
4570
- parseSystemQueryOption: function (sOption) {
4571
- return new _SystemQueryOptionParser().parse(sOption);
4578
+ parseSystemQueryOption: function (sOption, bParseFilter) {
4579
+ return new _SystemQueryOptionParser(bParseFilter).parse(sOption);
4572
4580
  },
4573
4581
  sODataIdentifier: sODataIdentifier,
4574
4582
  sWhitespace: sWhitespace
@@ -5151,7 +5159,7 @@ class LanguageTag {
5151
5159
  this.variant = (aResult[4] && aResult[4].slice(1)) || null; // remove leading hyphen from capturing group
5152
5160
  this.variantSubtags = this.variant ? this.variant.split('-') : [];
5153
5161
  this.extension = (aResult[5] && aResult[5].slice(1)) || null; // remove leading hyphen from capturing group
5154
- this.extensionSubtags = this.variant ? this.variant.split('-') : [];
5162
+ this.extensionSubtags = this.extension ? this.extension.split('-') : [];
5155
5163
  this.privateUse = aResult[6] || null;
5156
5164
  this.privateUseSubtags = this.privateUse ? this.privateUse.slice(2).split('-') : [];
5157
5165
  // convert subtags according to the BCP47 recommendations
@@ -6847,7 +6855,7 @@ _Helper = {
6847
6855
  });
6848
6856
  _Helper.fireChange(mChangeListeners, sPath, bRemoved ? undefined : oValue);
6849
6857
  },
6850
- formatLiteral: function (vValue, sType) {
6858
+ formatLiteral: function (vValue, sType, oTypeMetadata) {
6851
6859
  if (vValue === undefined) {
6852
6860
  throw new Error("Illegal value: undefined");
6853
6861
  }
@@ -6877,6 +6885,9 @@ _Helper = {
6877
6885
  case "Edm.String":
6878
6886
  return "'" + String(vValue).replace(rSingleQuote, "''") + "'";
6879
6887
  default:
6888
+ if (oTypeMetadata?.$kind === "EnumType") {
6889
+ return sType + "'" + vValue + "'";
6890
+ }
6880
6891
  throw new Error("Unsupported type: " + sType);
6881
6892
  }
6882
6893
  },
@@ -7007,7 +7018,7 @@ _Helper = {
7007
7018
  return sPath.replace(rNotMetaContext, "").slice(1);
7008
7019
  },
7009
7020
  getMissingPropertyPaths: function (vEntityOrCollection, mQueryOptions) {
7010
- return (mQueryOptions.$select || []).concat(Object.keys(mQueryOptions.$expand || ({}))).filter(function (sPath) {
7021
+ return (mQueryOptions.$select ?? []).concat(Object.keys(mQueryOptions.$expand ?? ({}))).filter(function (sPath) {
7011
7022
  return _Helper.isMissingProperty(vEntityOrCollection, sPath);
7012
7023
  });
7013
7024
  },
@@ -7044,7 +7055,7 @@ _Helper = {
7044
7055
  }
7045
7056
  });
7046
7057
  }
7047
- return mQueryOptions || ({});
7058
+ return mQueryOptions ?? ({});
7048
7059
  },
7049
7060
  getRelativePath: function (sPath, sBasePath) {
7050
7061
  if (sBasePath.length) {
@@ -7078,8 +7089,8 @@ _Helper = {
7078
7089
  }
7079
7090
  function isUsed(sPath, mQueryOptionsForPath) {
7080
7091
  let bPathMatchedExpand = false;
7081
- const aSelect = mQueryOptionsForPath.$select || ["*"];
7082
- const mExpand = mQueryOptionsForPath.$expand || ({});
7092
+ const aSelect = mQueryOptionsForPath.$select ?? ["*"];
7093
+ const mExpand = mQueryOptionsForPath.$expand ?? ({});
7083
7094
  return sPath === "*" || (sPath in mExpand) || aSelect.includes(sPath) || aSelect.some(sSelect => isRelated(sPath, sSelect)) || Object.keys(mExpand).some(sExpand => {
7084
7095
  if (_Helper.hasPathPrefix(sPath, sExpand)) {
7085
7096
  bPathMatchedExpand = true;
@@ -7160,7 +7171,7 @@ _Helper = {
7160
7171
  throw new Error("Unsupported empty navigation property path");
7161
7172
  }
7162
7173
  if (aPaths.includes("*")) {
7163
- aSelects = (mCacheQueryOptions && mCacheQueryOptions.$select || []).slice();
7174
+ aSelects = mCacheQueryOptions?.$select?.slice() ?? [];
7164
7175
  if (sMessagesPath && !aSelects.includes(sMessagesPath)) {
7165
7176
  aSelects.push(sMessagesPath);
7166
7177
  }
@@ -7188,7 +7199,7 @@ _Helper = {
7188
7199
  if (fnFetchMetadata(sMetaPath).getResult().$isCollection) {
7189
7200
  throw new Error("Unsupported collection-valued navigation property " + sMetaPath);
7190
7201
  }
7191
- mChildQueryOptions = _Helper.intersectQueryOptions(mCacheQueryOptions.$expand[sNavigationPropertyPath] || ({}), aStrippedPaths, fnFetchMetadata, sMetaPath, sPrefixedNavigationPropertyPath);
7202
+ mChildQueryOptions = _Helper.intersectQueryOptions(mCacheQueryOptions.$expand[sNavigationPropertyPath] ?? ({}), aStrippedPaths, fnFetchMetadata, sMetaPath, sPrefixedNavigationPropertyPath);
7192
7203
  if (mChildQueryOptions) {
7193
7204
  mExpands[sNavigationPropertyPath] = mChildQueryOptions;
7194
7205
  }
@@ -7421,14 +7432,14 @@ _Helper = {
7421
7432
  return mHeaders;
7422
7433
  },
7423
7434
  restoreUpdatingProperties: function (oOld, oNew) {
7424
- var oTempNew = oNew || ({});
7425
- Object.keys(oOld || ({})).forEach(function (sProperty) {
7435
+ for (const sProperty in oOld) {
7426
7436
  if (sProperty.startsWith("@")) {
7427
- return;
7437
+ continue;
7428
7438
  }
7429
7439
  if (Array.isArray(oOld[sProperty])) {
7430
- return;
7440
+ continue;
7431
7441
  }
7442
+ const oTempNew = oNew ?? ({});
7432
7443
  if (typeof oOld[sProperty] === "object") {
7433
7444
  oTempNew[sProperty] = _Helper.restoreUpdatingProperties(oOld[sProperty], oTempNew[sProperty]);
7434
7445
  }
@@ -7437,7 +7448,7 @@ _Helper = {
7437
7448
  oTempNew[sProperty + "@$ui5.updating"] = oOld[sProperty + "@$ui5.updating"];
7438
7449
  oNew = oTempNew;
7439
7450
  }
7440
- });
7451
+ }
7441
7452
  return oNew;
7442
7453
  },
7443
7454
  selectKeyProperties: function (mQueryOptions, oType) {
@@ -7506,7 +7517,7 @@ _Helper = {
7506
7517
  oTarget[sProperty] = vSourceProperty;
7507
7518
  _Helper.fireChange(mChangeListeners, sPropertyPath, vSourceProperty, false, true);
7508
7519
  } else if (vSourceProperty && typeof vSourceProperty === "object") {
7509
- vTargetProperty = oTarget[sProperty] = _Helper.updateAll(mChangeListeners, sPropertyPath, vTargetProperty || ({}), vSourceProperty);
7520
+ vTargetProperty = oTarget[sProperty] = _Helper.updateAll(mChangeListeners, sPropertyPath, vTargetProperty ?? ({}), vSourceProperty);
7510
7521
  _Helper.fireChange(mChangeListeners, sPropertyPath, vTargetProperty);
7511
7522
  } else if (vTargetProperty !== vSourceProperty) {
7512
7523
  oTarget[sProperty] = vSourceProperty;
@@ -7560,19 +7571,20 @@ _Helper = {
7560
7571
  updateNestedCreates: function (mChangeListeners, mQueryOptions, sPath, oTargetEntity, oCreatedEntity, mSelectForMetaPath) {
7561
7572
  let bDeepCreate = false;
7562
7573
  const mQueryOptionsForEntity = _Helper.getQueryOptionsForPath(mQueryOptions, sPath);
7563
- Object.keys(mQueryOptionsForEntity.$expand || ({})).forEach(function (sExpandPath) {
7574
+ for (const sExpandPath in mQueryOptionsForEntity.$expand) {
7564
7575
  const oNestedTargetEntity = _Helper.drillDown(oTargetEntity, sExpandPath);
7565
7576
  if (oNestedTargetEntity && !Array.isArray(oNestedTargetEntity)) {
7566
7577
  bDeepCreate = true;
7567
7578
  }
7568
- });
7569
- Object.keys(mSelectForMetaPath || ({})).filter(function (sMetaPath) {
7570
- return !sMetaPath.includes("/");
7571
- }).forEach(function (sSegment) {
7579
+ }
7580
+ for (const sSegment in mSelectForMetaPath) {
7581
+ if (sSegment.includes("/")) {
7582
+ continue;
7583
+ }
7572
7584
  const aNestedCreatedEntities = oCreatedEntity[sSegment];
7573
7585
  if (!aNestedCreatedEntities) {
7574
7586
  delete oTargetEntity[sSegment];
7575
- return;
7587
+ continue;
7576
7588
  }
7577
7589
  oTargetEntity[sSegment] = aNestedCreatedEntities;
7578
7590
  aNestedCreatedEntities.$count = undefined;
@@ -7596,7 +7608,7 @@ _Helper = {
7596
7608
  _Helper.updateNestedCreates(mChangeListeners, mQueryOptions, sCollectionPath + sPredicate, oCreatedChildEntity, oCreatedChildEntity, mSelectForChildMetaPath);
7597
7609
  });
7598
7610
  bDeepCreate = true;
7599
- });
7611
+ }
7600
7612
  return bDeepCreate;
7601
7613
  },
7602
7614
  updateNonExisting: function (oTarget, oSource) {
@@ -7657,7 +7669,7 @@ _Helper = {
7657
7669
  _Helper.fireChange(mChangeListeners, sPropertyPath, vSourceProperty, false, true);
7658
7670
  }
7659
7671
  } else if (vSourceProperty && typeof vSourceProperty === "object" && !sProperty.includes("@")) {
7660
- oTarget[sProperty] = update(sPropertyPath, vSelected, vTargetProperty || ({}), vSourceProperty);
7672
+ oTarget[sProperty] = update(sPropertyPath, vSelected, vTargetProperty ?? ({}), vSourceProperty);
7661
7673
  _Helper.fireChange(mChangeListeners, sPropertyPath, vSourceProperty);
7662
7674
  } else if (vTargetProperty !== vSourceProperty && !oTarget[sProperty + "@$ui5.updating"]) {
7663
7675
  oTarget[sProperty] = vSourceProperty;
@@ -8728,7 +8740,7 @@ _V2MetadataConverter.prototype.postProcessSchema = function (_oElement, _aResult
8728
8740
  continue;
8729
8741
  }
8730
8742
  sTarget = sEntityContainerName + "/" + sEntitySetName;
8731
- mAnnotations = _Helper$1.merge(this.convertedV2Annotations[sTarget] || ({}), this.mEntityType2EntitySetAnnotation[oEntitySet.$Type]);
8743
+ mAnnotations = _Helper$1.merge(this.convertedV2Annotations[sTarget] ?? ({}), this.mEntityType2EntitySetAnnotation[oEntitySet.$Type]);
8732
8744
  if (!_Helper$1.isEmptyObject(mAnnotations)) {
8733
8745
  this.convertedV2Annotations[sTarget] = mAnnotations;
8734
8746
  }
@@ -1,18 +1,12 @@
1
+ import ICachedResource from "./cachedResource.js";
1
2
  export default class CacheHolder {
2
3
  private static TEMP_TASK_DIR;
4
+ private static MERGED_DIR;
3
5
  static getTempDir(...paths: string[]): string;
4
- static read(repoName: string, token: string): Promise<Map<string, Buffer>>;
5
- /**
6
- * Read the most recently cached files for the given repo, without knowing
7
- * the cachebuster token up front. The @cached() decorator on
8
- * IRepository.fetch calls delete(repoName) before every write, so there is
9
- * at most one token subdirectory under <repoName>/ at any time.
10
- * Returns an empty map if the repo has never been fetched
11
- * (i.e. no full build has run yet).
12
- */
13
- static readLatest(repoName: string): Promise<Map<string, Buffer>>;
14
- static write(repoName: string, token: string, files: Map<string, Buffer>): Promise<void>;
15
- private static isValid;
6
+ static hasDirectory(resource: ICachedResource): Promise<boolean>;
7
+ static read(resource: ICachedResource): Promise<Map<string, Buffer>>;
8
+ static write(resource: ICachedResource, files: Map<string, Buffer>): Promise<void>;
9
+ static mergedResource(reference: string): ICachedResource;
16
10
  /**
17
11
  * Clears cached files by repo name and token
18
12
  */
@@ -8,50 +8,38 @@ import { getLogger } from "@ui5/logger";
8
8
  const log = getLogger("@ui5/task-adaptation::CacheHolder");
9
9
  export default class CacheHolder {
10
10
  static TEMP_TASK_DIR = "ui5-task-adaptation";
11
+ static MERGED_DIR = "merged";
11
12
  static getTempDir(...paths) {
12
13
  return path.join(os.tmpdir(), this.TEMP_TASK_DIR, ...paths.map(part => encodeFilename(part, { replacement: "_" })));
13
14
  }
14
- static read(repoName, token) {
15
- const directory = this.getTempDir(repoName, token);
16
- if (this.isValid(repoName, "repoName") && this.isValid(token, "token") && fs.existsSync(directory)) {
17
- return ResourceUtil.byGlob(directory, "**/*");
18
- }
19
- return Promise.resolve(new Map());
15
+ static async hasDirectory(resource) {
16
+ const directory = this.getTempDir(resource.appName, await resource.token);
17
+ return fs.existsSync(directory);
20
18
  }
21
- /**
22
- * Read the most recently cached files for the given repo, without knowing
23
- * the cachebuster token up front. The @cached() decorator on
24
- * IRepository.fetch calls delete(repoName) before every write, so there is
25
- * at most one token subdirectory under <repoName>/ at any time.
26
- * Returns an empty map if the repo has never been fetched
27
- * (i.e. no full build has run yet).
28
- */
29
- static async readLatest(repoName) {
30
- if (!this.isValid(repoName, "repoName")) {
31
- throw new Error(`Cache read requires 'repoName' to be provided`);
19
+ static async read(resource) {
20
+ const directory = this.getTempDir(resource.appName, await resource.token);
21
+ if (!await this.hasDirectory(resource)) {
22
+ log.verbose(`No cache directory '${directory}' found`);
23
+ return new Map();
32
24
  }
33
- const repoDir = this.getTempDir(repoName);
34
- if (!fs.existsSync(repoDir)) {
35
- throw new Error(`No cache found for '${repoName}'. Run a full build first.`);
25
+ return ResourceUtil.byGlob(directory, "**/*");
26
+ }
27
+ static async write(resource, files) {
28
+ const token = await resource.token;
29
+ if (resource.appName == null || token == null) {
30
+ log.verbose(`No 'appName' or 'token' provided, skipping cache write`);
31
+ return;
36
32
  }
37
- const [tokenDir] = await fsPromises.readdir(repoDir);
38
- if (!tokenDir) {
39
- throw new Error(`Cache directory for '${repoName}' is empty. Run a full build first.`);
33
+ if (!resource.keepAppNameDir) {
34
+ this.delete(resource.appName);
40
35
  }
41
- return ResourceUtil.byGlob(path.join(repoDir, tokenDir), "**/*");
42
- }
43
- static async write(repoName, token, files) {
44
- this.delete(repoName);
45
- if (this.isValid(repoName, "repoName") && this.isValid(token, "token")) {
46
- await ResourceUtil.write(this.getTempDir(repoName, token), files);
36
+ else {
37
+ this.delete(resource.appName, token);
47
38
  }
39
+ await ResourceUtil.write(this.getTempDir(resource.appName, token), files);
48
40
  }
49
- static isValid(value, name) {
50
- if (value == null || value === "") {
51
- log.warn(`No '${name}' provided, skipping cache write`);
52
- return false;
53
- }
54
- return true;
41
+ static mergedResource(reference) {
42
+ return { appName: reference, token: Promise.resolve(this.MERGED_DIR), keepAppNameDir: true };
55
43
  }
56
44
  /**
57
45
  * Clears cached files by repo name and token
@@ -91,14 +79,14 @@ export function cached() {
91
79
  const originalValue = descriptor.value;
92
80
  descriptor.value = async function (...args) {
93
81
  const cachedResource = args[0];
94
- const { appName, cacheBusterToken: cachebusterToken } = cachedResource;
95
- const token = await cachebusterToken;
96
- let files = await CacheHolder.read(appName, token);
82
+ let files = await CacheHolder.read(cachedResource);
83
+ const appName = cachedResource.appName;
84
+ const token = await cachedResource.token;
97
85
  CacheHolder.clearOutdatedExcept(appName);
98
86
  if (files.size === 0) {
99
87
  log.verbose(`No cache for repo '${appName}' with token '${token}'. Fetching from repository.`);
100
88
  files = await originalValue.apply(this, args);
101
- await CacheHolder.write(appName, token, files);
89
+ await CacheHolder.write(cachedResource, files);
102
90
  }
103
91
  else {
104
92
  log.verbose(`Using cached files for repo '${appName}' with token '${token}'.`);
@@ -1,4 +1,5 @@
1
1
  export default interface ICachedResource {
2
2
  appName: string;
3
- cacheBusterToken: Promise<string>;
3
+ token: Promise<string>;
4
+ keepAppNameDir?: boolean;
4
5
  }
package/dist/index.d.ts CHANGED
@@ -5,11 +5,10 @@ import { ITaskParameters } from "./model/types.js";
5
5
  declare const _default: ({ workspace, options, taskUtil }: ITaskParameters) => Promise<ReadonlyMap<string, Buffer<ArrayBufferLike>>>;
6
6
  export default _default;
7
7
  /**
8
- * Preview-time entry point (CF only). Produces the same manifest.json a
9
- * full build would produce, without going to the HTML5 Repo.
10
- * Precondition is a full build must have run at least once so the base app
11
- * files are cached by the @cached() decorator on HTML5Repository.fetch. If
12
- * the cache is empty, this throws with a message directing the user to run
13
- * a full build first.
8
+ * Produces the manifest.json a full build would produce, without a full UI5 build.
14
9
  */
15
10
  export declare function previewManifest({ workspace, options }: ITaskParameters): Promise<any>;
11
+ /**
12
+ * Downloads the base app and all resources along the app-variant hierarchy and writes the merged files to `outputDir`.
13
+ */
14
+ export declare function downloadAppResources({ workspace, options }: ITaskParameters, outputDir: string): Promise<void>;
package/dist/index.js CHANGED
@@ -1,7 +1,10 @@
1
1
  import * as dotenv from "dotenv";
2
- import { bufferToString, getReferences, logBuilderVersion } from "./util/commonUtil.js";
2
+ import { bufferToJson, logBuilderVersion } from "./util/commonUtil.js";
3
3
  import AppVariant from "./appVariant.js";
4
4
  import BaseApp from "./baseApp.js";
5
+ import CacheHolder from "./cache/cacheHolder.js";
6
+ import ResourceUtil from "./util/resourceUtil.js";
7
+ import ReferencesBuilder from "./util/referencesBuilder.js";
5
8
  import { initialize } from "./landscapeConfiguration.js";
6
9
  /**
7
10
  * Creates an appVariant bundle from the provided resources.
@@ -14,51 +17,55 @@ export default async ({ workspace, options, taskUtil }) => {
14
17
  };
15
18
  dotenv.config();
16
19
  logBuilderVersion();
17
- const { repository, adapter } = await initialize(options.configuration);
20
+ const { adapter, repository } = await initialize(options.configuration);
18
21
  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}`);
24
- }
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 appVariantFilesPromise of fetchFilesPromises) {
38
- const appVariantFiles = await appVariantFilesPromise;
39
- files = await adapt(files, AppVariant.fromFiles(appVariantFiles));
40
- }
41
- files = await adapt(files, adaptationProject);
42
- const references = getReferences(appVariants, adaptationProject.id);
22
+ const { files: baseFiles } = await foldBaseHierarchy(adapter, repository, adaptationProject.reference);
23
+ await CacheHolder.write(CacheHolder.mergedResource(adaptationProject.reference), new Map(baseFiles));
24
+ const files = await adapter.createAdaptCommandChain(baseFiles, adaptationProject).execute();
25
+ const references = new ReferencesBuilder()
26
+ .addReferences(files, adaptationProject.id)
27
+ .build();
43
28
  return adapter.createPostCommandChain(references, adaptationProject, ui5BuilderTools).execute(files);
44
29
  };
45
30
  /**
46
- * Preview-time entry point (CF only). Produces the same manifest.json a
47
- * full build would produce, without going to the HTML5 Repo.
48
- * Precondition is a full build must have run at least once so the base app
49
- * files are cached by the @cached() decorator on HTML5Repository.fetch. If
50
- * the cache is empty, this throws with a message directing the user to run
51
- * a full build first.
31
+ * Produces the manifest.json a full build would produce, without a full UI5 build.
52
32
  */
53
33
  export async function previewManifest({ workspace, options }) {
54
- const { repository, adapter } = await initialize(options.configuration, { useCacheRepository: true });
34
+ const { adapter, repository } = await initialize(options.configuration, { useCache: true });
35
+ const adaptationProject = await AppVariant.fromWorkspace(workspace, options.projectNamespace);
36
+ const { files: baseFiles } = await foldBaseHierarchy(adapter, repository, adaptationProject.reference);
37
+ await CacheHolder.write(CacheHolder.mergedResource(adaptationProject.reference), new Map(baseFiles));
38
+ const baseApp = BaseApp.fromFiles(baseFiles);
39
+ const references = new ReferencesBuilder()
40
+ .addReference(adaptationProject.reference, adaptationProject.id)
41
+ .addReferences(baseFiles, adaptationProject.id)
42
+ .build();
43
+ const files = new Map(baseFiles);
44
+ await adapter.createManifestPreviewCommandChain(baseApp, adaptationProject, references).execute(files, "manifest.json");
45
+ return bufferToJson(files.get("manifest.json"));
46
+ }
47
+ /**
48
+ * Downloads the base app and all resources along the app-variant hierarchy and writes the merged files to `outputDir`.
49
+ */
50
+ export async function downloadAppResources({ workspace, options }, outputDir) {
51
+ const { adapter, repository } = await initialize(options.configuration);
55
52
  const adaptationProject = await AppVariant.fromWorkspace(workspace, options.projectNamespace);
56
- const [baseAppResource] = await repository.getAppVariantIdHierarchy(adaptationProject.reference);
57
- const cachedBaseAppFiles = await repository.fetch(baseAppResource);
58
- const baseApp = BaseApp.fromFiles(cachedBaseAppFiles);
59
- const files = new Map(cachedBaseAppFiles);
60
- const manifestPreviewCommandChain = adapter.createManifestPreviewCommandChain(baseApp, adaptationProject);
61
- await manifestPreviewCommandChain.execute(files, "manifest.json");
62
- return JSON.parse(bufferToString(files.get("manifest.json")));
53
+ const { files } = await foldBaseHierarchy(adapter, repository, adaptationProject.reference);
54
+ await ResourceUtil.write(outputDir, new Map(files));
55
+ }
56
+ async function foldBaseHierarchy(adapter, repository, reference) {
57
+ await adapter.createSetupCommandChain(reference, repository).execute();
58
+ const hierarchy = await repository.getAppVariantIdHierarchy(reference);
59
+ if (hierarchy.length === 0) {
60
+ throw new Error(`No app variant found for reference ${reference}`);
61
+ }
62
+ const fetchFilesPromises = hierarchy.toReversed()
63
+ .map(variant => repository.fetch(variant));
64
+ let files = await fetchFilesPromises.shift(); // original base app files
65
+ for (const filesPromise of fetchFilesPromises) {
66
+ const appVariant = AppVariant.fromFiles(await filesPromise);
67
+ files = await adapter.createAdaptCommandChain(files, appVariant).execute();
68
+ }
69
+ return { files };
63
70
  }
64
71
  //# sourceMappingURL=index.js.map
@@ -1,9 +1,9 @@
1
- import { IConfiguration, IInitializeOptions } from "./model/types.js";
1
+ import { IConfiguration } from "./model/types.js";
2
2
  import { IAdapter } from "./adapters/adapter.js";
3
3
  import IRepository from "./repositories/repository.js";
4
- import IAnnotationManager from "./annotations/annotationManager.js";
5
- export declare function initialize(configuration: IConfiguration, options?: IInitializeOptions): Promise<{
4
+ export declare function initialize(configuration: IConfiguration, options?: {
5
+ useCache?: boolean;
6
+ }): Promise<{
6
7
  adapter: IAdapter;
7
8
  repository: IRepository;
8
- annotationManager: IAnnotationManager;
9
9
  }>;
@@ -8,12 +8,16 @@ const log = getLogger("@ui5/task-adaptation::LandscapeConfiguration");
8
8
  export async function initialize(configuration, options = {}) {
9
9
  const type = await getTypeByConfiguration(configuration);
10
10
  const enhancedConfig = { ...configuration, type };
11
- const repository = await getRepository(enhancedConfig, options);
11
+ let repository = await getRepository(enhancedConfig);
12
12
  const annotationManager = await getAnnotationManager(enhancedConfig, repository);
13
+ if (options.useCache) {
14
+ const { default: CacheRepository } = await import("./repositories/cacheRepository.js");
15
+ repository = new CacheRepository(repository);
16
+ }
17
+ const adapter = await getAdapter(enhancedConfig, annotationManager);
13
18
  return {
14
- adapter: await getAdapter(enhancedConfig, annotationManager),
15
- repository,
16
- annotationManager
19
+ adapter,
20
+ repository
17
21
  };
18
22
  }
19
23
  async function getTypeByConfiguration(configuration) {
@@ -38,62 +42,62 @@ async function getTypeByConfiguration(configuration) {
38
42
  throw new Error("'type' should be specified in ui5.yaml configuration: 'cf' or 'abap'");
39
43
  }
40
44
  }
41
- async function getAdapter(configuration, annotationManager) {
42
- if (isPreview()) {
43
- const { default: PreviewAdapter } = await import("./adapters/previewAdapter.js");
44
- return new PreviewAdapter(configuration);
45
- }
46
- switch (configuration.type) {
47
- case "abap": {
45
+ const LANDSCAPE_FACTORIES = {
46
+ abap: {
47
+ adapter: async (_configuration, annotationManager) => {
48
48
  const { default: AbapAdapter } = await import("./adapters/abapAdapter.js");
49
49
  return new AbapAdapter(annotationManager);
50
- }
51
- case "cf": {
50
+ },
51
+ repository: async (configuration) => {
52
+ const { default: AbapRepository } = await import("./repositories/abapRepository.js");
53
+ return new AbapRepository(configuration);
54
+ },
55
+ annotationManager: async (configuration, repository) => {
56
+ const { default: AbapAnnotationManager } = await import("./annotations/abapAnnotationManager.js");
57
+ return new AbapAnnotationManager(configuration, repository);
58
+ },
59
+ },
60
+ cf: {
61
+ adapter: async (configuration) => {
52
62
  const { default: CFAdapter } = await import("./adapters/cfAdapter.js");
53
63
  return new CFAdapter(configuration);
54
- }
55
- default:
56
- throw new Error(`No adapter found for the given configuration type '${configuration.type}'`);
64
+ },
65
+ repository: async (configuration) => {
66
+ const { default: HTML5Repository } = await import("./repositories/html5Repository.js");
67
+ return new HTML5Repository(configuration);
68
+ },
69
+ annotationManager: async () => {
70
+ const { default: CFAnnotationManager } = await import("./annotations/cfAnnotationManager.js");
71
+ return new CFAnnotationManager();
72
+ },
73
+ },
74
+ };
75
+ function landscapeFactory(configuration) {
76
+ const factory = LANDSCAPE_FACTORIES[configuration.type];
77
+ if (!factory) {
78
+ throw new Error(`No landscape factory found for the given configuration type '${configuration.type}'`);
57
79
  }
80
+ return factory;
58
81
  }
59
- async function getRepository(configuration, options) {
60
- if (options.useCacheRepository) {
61
- const { default: CacheRepository } = await import("./repositories/cacheRepository.js");
62
- return new CacheRepository(configuration);
82
+ async function getAdapter(configuration, annotationManager) {
83
+ if (isPreview()) {
84
+ const { default: PreviewAdapter } = await import("./adapters/previewAdapter.js");
85
+ return new PreviewAdapter(configuration);
63
86
  }
87
+ return landscapeFactory(configuration).adapter(configuration, annotationManager);
88
+ }
89
+ async function getRepository(configuration) {
64
90
  if (isLocal()) {
65
91
  const { default: LocalRepository } = await import("./repositories/localRepository.js");
66
92
  return new LocalRepository();
67
93
  }
68
- switch (configuration.type) {
69
- case "abap": {
70
- const { default: AbapRepository } = await import("./repositories/abapRepository.js");
71
- return new AbapRepository(configuration);
72
- }
73
- case "cf": {
74
- const { default: HTML5Repository } = await import("./repositories/html5Repository.js");
75
- return new HTML5Repository(configuration);
76
- }
77
- default:
78
- throw new Error(`No repository found for the given configuration type '${configuration.type}'`);
79
- }
94
+ return landscapeFactory(configuration).repository(configuration);
80
95
  }
81
96
  async function getAnnotationManager(configuration, repository) {
82
97
  if (isLocal()) {
83
98
  return new LocalAnnotationManager();
84
99
  }
85
- switch (configuration.type) {
86
- case "abap": {
87
- const { default: AbapAnnotationManager } = await import("./annotations/abapAnnotationManager.js");
88
- return new AbapAnnotationManager(configuration, repository);
89
- }
90
- case "cf": {
91
- const { default: CFAnnotationManager } = await import("./annotations/cfAnnotationManager.js");
92
- return new CFAnnotationManager();
93
- }
94
- default:
95
- throw new Error(`No annotation manager found for the given configuration type '${configuration.type}'`);
96
- }
100
+ return landscapeFactory(configuration).annotationManager(configuration, repository);
97
101
  }
98
102
  function isLocal() {
99
103
  return process.env.ADP_BUILDER_MODE === "local";
@@ -12,7 +12,6 @@ export interface IConfiguration {
12
12
  languages?: any[] | undefined;
13
13
  enableAnnotationCache?: boolean;
14
14
  enableBetaFeatures?: boolean;
15
- writeTempFiles?: any;
16
15
  target?: AbapTarget & IAbapTargetMeta;
17
16
  serviceInstanceName?: string;
18
17
  }
@@ -132,6 +132,3 @@ export type ServiceCredentials = {
132
132
  };
133
133
  export type FetchFilesPromise = Map<string, Promise<ReadonlyMap<string, Buffer>>>;
134
134
  export { IConfiguration };
135
- export interface IInitializeOptions {
136
- useCacheRepository?: boolean;
137
- }
@@ -9,7 +9,7 @@ export default class AbapRepository implements IRepository {
9
9
  constructor(configuration: IConfiguration, abapProvider?: AbapProvider);
10
10
  getAppVariantIdHierarchy(id: string): Promise<IAbapResource[]>;
11
11
  getAnnotationMetadata(uri: string): Promise<IMetadata>;
12
- downloadAnnotationFile(uri: string): Promise<Map<string, any>>;
12
+ downloadAnnotationFile(uri: string): Promise<any>;
13
13
  getMetadata(id: string): Promise<IMetadata>;
14
14
  fetch(resource: IAbapResource): Promise<Map<string, Buffer>>;
15
15
  }
@@ -37,14 +37,14 @@ export default class AbapRepository {
37
37
  const hierarchy = JSON.parse(response.data)?.appVariantIdHierarchy;
38
38
  return hierarchy.map(item => ({
39
39
  appName: item.repoName,
40
- cacheBusterToken: Promise.resolve(item.cachebusterToken)
40
+ token: Promise.resolve(item.cachebusterToken)
41
41
  }));
42
42
  }
43
43
  else if (this.configuration.appName) {
44
44
  // Fallback to old API on old ABAP backend or CF for backward compatibility
45
45
  return [{
46
46
  appName: this.configuration.appName,
47
- cacheBusterToken: this.getMetadata(id).then(metadata => metadata.changedOn),
47
+ token: this.getMetadata(id).then(metadata => metadata.changedOn),
48
48
  }];
49
49
  }
50
50
  throw new Error(`App variant id hierarchy for app id '${id}' is not provided`);
@@ -59,7 +59,7 @@ export default class AbapRepository {
59
59
  const response = await provider.get(uri, {
60
60
  headers: REQUEST_OPTIONS_XML.headers
61
61
  });
62
- return new Map([["annotation.xml", response.data]]);
62
+ return response.data;
63
63
  }
64
64
  async getMetadata(id) {
65
65
  const provider = await this.abapProvider.get(this.configuration);