@ui5/task-adaptation 1.6.7 → 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 (74) 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 +42 -36
  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 -7
  31. package/dist/appVariant.js +9 -23
  32. package/dist/baseApp.d.ts +1 -0
  33. package/dist/baseApp.js +10 -0
  34. package/dist/bundle.js +86 -53
  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 +6 -7
  39. package/dist/index.js +49 -42
  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 +1 -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/cfUtil.d.ts +6 -24
  54. package/dist/util/cfUtil.js +36 -93
  55. package/dist/util/commonUtil.d.ts +1 -9
  56. package/dist/util/commonUtil.js +27 -29
  57. package/dist/util/fsUtil.js +1 -2
  58. package/dist/util/movingHandler/changeFileMoveHandler.d.ts +1 -0
  59. package/dist/util/movingHandler/changeFileMoveHandler.js +11 -3
  60. package/dist/util/referencesBuilder.d.ts +15 -0
  61. package/dist/util/referencesBuilder.js +35 -0
  62. package/dist/util/renaming/fileRenamer.d.ts +23 -0
  63. package/dist/util/renaming/fileRenamer.js +120 -0
  64. package/dist/util/{renamingHandlers → renaming/handlers}/jsonRenamingHandler.d.ts +0 -2
  65. package/dist/util/{renamingHandlers → renaming/handlers}/jsonRenamingHandler.js +0 -6
  66. package/dist/util/{renamingUtil.d.ts → renaming/referenceRenaming.d.ts} +4 -4
  67. package/dist/util/{renamingUtil.js → renaming/referenceRenaming.js} +8 -8
  68. package/dist/util/resourceUtil.js +6 -2
  69. package/package.json +11 -4
  70. package/release-please-config.json +66 -0
  71. package/dist/annotations/serviceRequestor.d.ts +0 -9
  72. package/dist/annotations/serviceRequestor.js +0 -62
  73. /package/dist/util/{renamingHandlers → renaming/handlers}/manifestRenamingHandler.d.ts +0 -0
  74. /package/dist/util/{renamingHandlers → renaming/handlers}/manifestRenamingHandler.js +0 -0
package/dist/bundle.js CHANGED
@@ -2183,34 +2183,52 @@ function processTerminologies(oChangeContent, sAppId) {
2183
2183
  });
2184
2184
  }
2185
2185
  }
2186
+ function getEnhancementSettings(oChange, oChangeContent, sAppId) {
2187
+ const sI18n = oChange.getTexts()?.i18n;
2188
+ if (sI18n) {
2189
+ return {
2190
+ bundleName: ApplyUtil.formatBundleName(sAppId, sI18n)
2191
+ };
2192
+ }
2193
+ const oEnhancementSettings = Object.assign({}, oChangeContent);
2194
+ oEnhancementSettings.terminologies &&= Object.keys(oEnhancementSettings.terminologies).reduce((oResult, sTerminology) => {
2195
+ oResult[sTerminology] = Object.assign({}, oEnhancementSettings.terminologies[sTerminology]);
2196
+ return oResult;
2197
+ }, {});
2198
+ if (hasBundleUrlAndNotBundleName(oEnhancementSettings)) {
2199
+ oEnhancementSettings.bundleName = ApplyUtil.formatBundleName(sAppId, oEnhancementSettings.bundleUrl);
2200
+ delete oEnhancementSettings.bundleUrl;
2201
+ }
2202
+ processTerminologies(oEnhancementSettings, sAppId);
2203
+ delete oEnhancementSettings.modelId;
2204
+ delete oEnhancementSettings.createIfMissing;
2205
+ return oEnhancementSettings;
2206
+ }
2186
2207
  const AddNewModelEnhanceWith = {
2187
2208
  applyChange(oManifest, oChange) {
2188
2209
  const oChangeContent = oChange.getContent();
2189
2210
  const sModelId = oChangeContent.modelId;
2190
- const oModel = oManifest["sap.ui5"].models[sModelId];
2191
- if (oModel) {
2192
- if (oModel.type && oModel.type === "sap.ui.model.resource.ResourceModel") {
2193
- if (!(oModel.settings && oModel.settings.enhanceWith)) {
2194
- ObjectPath.set("settings.enhanceWith", [], oModel);
2195
- }
2196
- const sAppId = oManifest["sap.app"].id;
2197
- const sI18n = oChange.getTexts()?.i18n;
2198
- const oEnhanceWith = oModel.settings.enhanceWith;
2199
- if (sI18n) {
2200
- oEnhanceWith.push({
2201
- bundleName: ApplyUtil.formatBundleName(sAppId, sI18n)
2202
- });
2203
- return oManifest;
2204
- }
2205
- if (hasBundleUrlAndNotBundleName(oChangeContent)) {
2206
- oChangeContent.bundleName = ApplyUtil.formatBundleName(sAppId, oChangeContent.bundleUrl);
2207
- delete oChangeContent.bundleUrl;
2208
- }
2209
- processTerminologies(oChangeContent, sAppId);
2210
- delete oChangeContent.modelId;
2211
- if (Object.keys(oChangeContent).length > 0) {
2212
- oEnhanceWith.push(oChangeContent);
2213
- }
2211
+ const oModels = oManifest["sap.ui5"].models;
2212
+ const sAppId = oManifest["sap.app"].id;
2213
+ const oEnhancementSettings = getEnhancementSettings(oChange, oChangeContent, sAppId);
2214
+ const oModel = oModels[sModelId];
2215
+ if (!oModel) {
2216
+ if (!oChangeContent.createIfMissing) {
2217
+ throw Error(`Model with ID '${sModelId}' does not exist. Set createIfMissing to true to create it.`);
2218
+ }
2219
+ oModels[sModelId] = {
2220
+ type: "sap.ui.model.resource.ResourceModel",
2221
+ settings: oEnhancementSettings
2222
+ };
2223
+ return oManifest;
2224
+ }
2225
+ if (oModel.type && oModel.type === "sap.ui.model.resource.ResourceModel") {
2226
+ if (!(oModel.settings && oModel.settings.enhanceWith)) {
2227
+ ObjectPath.set("settings.enhanceWith", [], oModel);
2228
+ }
2229
+ const oEnhanceWith = oModel.settings.enhanceWith;
2230
+ if (!fnIsEmptyObject(oEnhancementSettings)) {
2231
+ oEnhanceWith.push(oEnhancementSettings);
2214
2232
  }
2215
2233
  }
2216
2234
  return oManifest;
@@ -2303,7 +2321,7 @@ function Version(vMajor, iMinor, iPatch, sSuffix) {
2303
2321
  return sSuffix;
2304
2322
  };
2305
2323
  this.compareTo = function (vOtherMajor, iOtherMinor, iOtherPatch, sOtherSuffix) {
2306
- var vOther = Version.apply(window, arguments);
2324
+ var vOther = Version.apply(null, arguments);
2307
2325
  return vMajor - vOther.getMajor() || iMinor - vOther.getMinor() || iPatch - vOther.getPatch() || (sSuffix < vOther.getSuffix() ? -1 : sSuffix === vOther.getSuffix() ? 0 : 1);
2308
2326
  };
2309
2327
  }
@@ -4324,8 +4342,9 @@ _KeyPredicateParser.prototype.parse = function (sKeyPredicate) {
4324
4342
  this.finish();
4325
4343
  return oKeyProperties;
4326
4344
  };
4327
- function _SystemQueryOptionParser() {
4345
+ function _SystemQueryOptionParser(bParseFilter) {
4328
4346
  _Parser.apply(this, arguments);
4347
+ this.oFilterParser = bParseFilter ? new _FilterParser() : undefined;
4329
4348
  }
4330
4349
  _SystemQueryOptionParser.prototype = Object.create(_Parser.prototype);
4331
4350
  _SystemQueryOptionParser.prototype.parse = function (sOption) {
@@ -4411,10 +4430,17 @@ _SystemQueryOptionParser.prototype.parseSelect = function () {
4411
4430
  };
4412
4431
  };
4413
4432
  _SystemQueryOptionParser.prototype.parseSystemQueryOption = function () {
4414
- var oToken = this.advance("OPTION");
4433
+ const oToken = this.advance("OPTION");
4415
4434
  switch (oToken.value) {
4416
4435
  case "$expand":
4417
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
+ }
4418
4444
  case "$select":
4419
4445
  return this.parseSelect();
4420
4446
  default:
@@ -4549,8 +4575,8 @@ var _Parser$1 = {
4549
4575
  parseKeyPredicate: function (sKeyPredicate) {
4550
4576
  return new _KeyPredicateParser().parse(sKeyPredicate);
4551
4577
  },
4552
- parseSystemQueryOption: function (sOption) {
4553
- return new _SystemQueryOptionParser().parse(sOption);
4578
+ parseSystemQueryOption: function (sOption, bParseFilter) {
4579
+ return new _SystemQueryOptionParser(bParseFilter).parse(sOption);
4554
4580
  },
4555
4581
  sODataIdentifier: sODataIdentifier,
4556
4582
  sWhitespace: sWhitespace
@@ -4598,7 +4624,7 @@ var fnEqual = function (a, b, maxDepth, contains, depth) {
4598
4624
  if (!contains && Object.keys(a).length !== Object.keys(b).length) {
4599
4625
  return false;
4600
4626
  }
4601
- if (a instanceof Node) {
4627
+ if (typeof Node !== "undefined" && a instanceof Node) {
4602
4628
  return a.isEqualNode(b);
4603
4629
  }
4604
4630
  if (a instanceof Date) {
@@ -5133,7 +5159,7 @@ class LanguageTag {
5133
5159
  this.variant = (aResult[4] && aResult[4].slice(1)) || null; // remove leading hyphen from capturing group
5134
5160
  this.variantSubtags = this.variant ? this.variant.split('-') : [];
5135
5161
  this.extension = (aResult[5] && aResult[5].slice(1)) || null; // remove leading hyphen from capturing group
5136
- this.extensionSubtags = this.variant ? this.variant.split('-') : [];
5162
+ this.extensionSubtags = this.extension ? this.extension.split('-') : [];
5137
5163
  this.privateUse = aResult[6] || null;
5138
5164
  this.privateUseSubtags = this.privateUse ? this.privateUse.slice(2).split('-') : [];
5139
5165
  // convert subtags according to the BCP47 recommendations
@@ -6713,6 +6739,9 @@ _Helper = {
6713
6739
  return oCurrent && (sSegment in oCurrent) ? oCurrent[sSegment] : undefined;
6714
6740
  }, oObject);
6715
6741
  },
6742
+ dropQuery: function (sResourcePathWithQuery) {
6743
+ return sResourcePathWithQuery.split("?")[0];
6744
+ },
6716
6745
  encode: function (sPart, bEncodeEquals) {
6717
6746
  var sEncoded = encodeURI(sPart).replace(rAmpersand, "%26").replace(rHash, "%23").replace(rPlus, "%2B");
6718
6747
  if (bEncodeEquals) {
@@ -6826,7 +6855,7 @@ _Helper = {
6826
6855
  });
6827
6856
  _Helper.fireChange(mChangeListeners, sPath, bRemoved ? undefined : oValue);
6828
6857
  },
6829
- formatLiteral: function (vValue, sType) {
6858
+ formatLiteral: function (vValue, sType, oTypeMetadata) {
6830
6859
  if (vValue === undefined) {
6831
6860
  throw new Error("Illegal value: undefined");
6832
6861
  }
@@ -6856,6 +6885,9 @@ _Helper = {
6856
6885
  case "Edm.String":
6857
6886
  return "'" + String(vValue).replace(rSingleQuote, "''") + "'";
6858
6887
  default:
6888
+ if (oTypeMetadata?.$kind === "EnumType") {
6889
+ return sType + "'" + vValue + "'";
6890
+ }
6859
6891
  throw new Error("Unsupported type: " + sType);
6860
6892
  }
6861
6893
  },
@@ -6986,7 +7018,7 @@ _Helper = {
6986
7018
  return sPath.replace(rNotMetaContext, "").slice(1);
6987
7019
  },
6988
7020
  getMissingPropertyPaths: function (vEntityOrCollection, mQueryOptions) {
6989
- return (mQueryOptions.$select || []).concat(Object.keys(mQueryOptions.$expand || ({}))).filter(function (sPath) {
7021
+ return (mQueryOptions.$select ?? []).concat(Object.keys(mQueryOptions.$expand ?? ({}))).filter(function (sPath) {
6990
7022
  return _Helper.isMissingProperty(vEntityOrCollection, sPath);
6991
7023
  });
6992
7024
  },
@@ -7023,7 +7055,7 @@ _Helper = {
7023
7055
  }
7024
7056
  });
7025
7057
  }
7026
- return mQueryOptions || ({});
7058
+ return mQueryOptions ?? ({});
7027
7059
  },
7028
7060
  getRelativePath: function (sPath, sBasePath) {
7029
7061
  if (sBasePath.length) {
@@ -7057,8 +7089,8 @@ _Helper = {
7057
7089
  }
7058
7090
  function isUsed(sPath, mQueryOptionsForPath) {
7059
7091
  let bPathMatchedExpand = false;
7060
- const aSelect = mQueryOptionsForPath.$select || ["*"];
7061
- const mExpand = mQueryOptionsForPath.$expand || ({});
7092
+ const aSelect = mQueryOptionsForPath.$select ?? ["*"];
7093
+ const mExpand = mQueryOptionsForPath.$expand ?? ({});
7062
7094
  return sPath === "*" || (sPath in mExpand) || aSelect.includes(sPath) || aSelect.some(sSelect => isRelated(sPath, sSelect)) || Object.keys(mExpand).some(sExpand => {
7063
7095
  if (_Helper.hasPathPrefix(sPath, sExpand)) {
7064
7096
  bPathMatchedExpand = true;
@@ -7139,7 +7171,7 @@ _Helper = {
7139
7171
  throw new Error("Unsupported empty navigation property path");
7140
7172
  }
7141
7173
  if (aPaths.includes("*")) {
7142
- aSelects = (mCacheQueryOptions && mCacheQueryOptions.$select || []).slice();
7174
+ aSelects = mCacheQueryOptions?.$select?.slice() ?? [];
7143
7175
  if (sMessagesPath && !aSelects.includes(sMessagesPath)) {
7144
7176
  aSelects.push(sMessagesPath);
7145
7177
  }
@@ -7167,7 +7199,7 @@ _Helper = {
7167
7199
  if (fnFetchMetadata(sMetaPath).getResult().$isCollection) {
7168
7200
  throw new Error("Unsupported collection-valued navigation property " + sMetaPath);
7169
7201
  }
7170
- mChildQueryOptions = _Helper.intersectQueryOptions(mCacheQueryOptions.$expand[sNavigationPropertyPath] || ({}), aStrippedPaths, fnFetchMetadata, sMetaPath, sPrefixedNavigationPropertyPath);
7202
+ mChildQueryOptions = _Helper.intersectQueryOptions(mCacheQueryOptions.$expand[sNavigationPropertyPath] ?? ({}), aStrippedPaths, fnFetchMetadata, sMetaPath, sPrefixedNavigationPropertyPath);
7171
7203
  if (mChildQueryOptions) {
7172
7204
  mExpands[sNavigationPropertyPath] = mChildQueryOptions;
7173
7205
  }
@@ -7400,14 +7432,14 @@ _Helper = {
7400
7432
  return mHeaders;
7401
7433
  },
7402
7434
  restoreUpdatingProperties: function (oOld, oNew) {
7403
- var oTempNew = oNew || ({});
7404
- Object.keys(oOld || ({})).forEach(function (sProperty) {
7435
+ for (const sProperty in oOld) {
7405
7436
  if (sProperty.startsWith("@")) {
7406
- return;
7437
+ continue;
7407
7438
  }
7408
7439
  if (Array.isArray(oOld[sProperty])) {
7409
- return;
7440
+ continue;
7410
7441
  }
7442
+ const oTempNew = oNew ?? ({});
7411
7443
  if (typeof oOld[sProperty] === "object") {
7412
7444
  oTempNew[sProperty] = _Helper.restoreUpdatingProperties(oOld[sProperty], oTempNew[sProperty]);
7413
7445
  }
@@ -7416,7 +7448,7 @@ _Helper = {
7416
7448
  oTempNew[sProperty + "@$ui5.updating"] = oOld[sProperty + "@$ui5.updating"];
7417
7449
  oNew = oTempNew;
7418
7450
  }
7419
- });
7451
+ }
7420
7452
  return oNew;
7421
7453
  },
7422
7454
  selectKeyProperties: function (mQueryOptions, oType) {
@@ -7485,7 +7517,7 @@ _Helper = {
7485
7517
  oTarget[sProperty] = vSourceProperty;
7486
7518
  _Helper.fireChange(mChangeListeners, sPropertyPath, vSourceProperty, false, true);
7487
7519
  } else if (vSourceProperty && typeof vSourceProperty === "object") {
7488
- vTargetProperty = oTarget[sProperty] = _Helper.updateAll(mChangeListeners, sPropertyPath, vTargetProperty || ({}), vSourceProperty);
7520
+ vTargetProperty = oTarget[sProperty] = _Helper.updateAll(mChangeListeners, sPropertyPath, vTargetProperty ?? ({}), vSourceProperty);
7489
7521
  _Helper.fireChange(mChangeListeners, sPropertyPath, vTargetProperty);
7490
7522
  } else if (vTargetProperty !== vSourceProperty) {
7491
7523
  oTarget[sProperty] = vSourceProperty;
@@ -7539,19 +7571,20 @@ _Helper = {
7539
7571
  updateNestedCreates: function (mChangeListeners, mQueryOptions, sPath, oTargetEntity, oCreatedEntity, mSelectForMetaPath) {
7540
7572
  let bDeepCreate = false;
7541
7573
  const mQueryOptionsForEntity = _Helper.getQueryOptionsForPath(mQueryOptions, sPath);
7542
- Object.keys(mQueryOptionsForEntity.$expand || ({})).forEach(function (sExpandPath) {
7574
+ for (const sExpandPath in mQueryOptionsForEntity.$expand) {
7543
7575
  const oNestedTargetEntity = _Helper.drillDown(oTargetEntity, sExpandPath);
7544
7576
  if (oNestedTargetEntity && !Array.isArray(oNestedTargetEntity)) {
7545
7577
  bDeepCreate = true;
7546
7578
  }
7547
- });
7548
- Object.keys(mSelectForMetaPath || ({})).filter(function (sMetaPath) {
7549
- return !sMetaPath.includes("/");
7550
- }).forEach(function (sSegment) {
7579
+ }
7580
+ for (const sSegment in mSelectForMetaPath) {
7581
+ if (sSegment.includes("/")) {
7582
+ continue;
7583
+ }
7551
7584
  const aNestedCreatedEntities = oCreatedEntity[sSegment];
7552
7585
  if (!aNestedCreatedEntities) {
7553
7586
  delete oTargetEntity[sSegment];
7554
- return;
7587
+ continue;
7555
7588
  }
7556
7589
  oTargetEntity[sSegment] = aNestedCreatedEntities;
7557
7590
  aNestedCreatedEntities.$count = undefined;
@@ -7575,7 +7608,7 @@ _Helper = {
7575
7608
  _Helper.updateNestedCreates(mChangeListeners, mQueryOptions, sCollectionPath + sPredicate, oCreatedChildEntity, oCreatedChildEntity, mSelectForChildMetaPath);
7576
7609
  });
7577
7610
  bDeepCreate = true;
7578
- });
7611
+ }
7579
7612
  return bDeepCreate;
7580
7613
  },
7581
7614
  updateNonExisting: function (oTarget, oSource) {
@@ -7636,7 +7669,7 @@ _Helper = {
7636
7669
  _Helper.fireChange(mChangeListeners, sPropertyPath, vSourceProperty, false, true);
7637
7670
  }
7638
7671
  } else if (vSourceProperty && typeof vSourceProperty === "object" && !sProperty.includes("@")) {
7639
- oTarget[sProperty] = update(sPropertyPath, vSelected, vTargetProperty || ({}), vSourceProperty);
7672
+ oTarget[sProperty] = update(sPropertyPath, vSelected, vTargetProperty ?? ({}), vSourceProperty);
7640
7673
  _Helper.fireChange(mChangeListeners, sPropertyPath, vSourceProperty);
7641
7674
  } else if (vTargetProperty !== vSourceProperty && !oTarget[sProperty + "@$ui5.updating"]) {
7642
7675
  oTarget[sProperty] = vSourceProperty;
@@ -8707,7 +8740,7 @@ _V2MetadataConverter.prototype.postProcessSchema = function (_oElement, _aResult
8707
8740
  continue;
8708
8741
  }
8709
8742
  sTarget = sEntityContainerName + "/" + sEntitySetName;
8710
- mAnnotations = _Helper$1.merge(this.convertedV2Annotations[sTarget] || ({}), this.mEntityType2EntitySetAnnotation[oEntitySet.$Type]);
8743
+ mAnnotations = _Helper$1.merge(this.convertedV2Annotations[sTarget] ?? ({}), this.mEntityType2EntitySetAnnotation[oEntitySet.$Type]);
8711
8744
  if (!_Helper$1.isEmptyObject(mAnnotations)) {
8712
8745
  this.convertedV2Annotations[sTarget] = mAnnotations;
8713
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
- export declare function previewManifest({ options }: ITaskParameters): Promise<any>;
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
- export async function previewManifest({ options }) {
54
- const { repository, adapter } = await initialize(options.configuration, { useCacheRepository: true });
55
- const adaptationProject = await AppVariant.fromProject();
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")));
33
+ export async function previewManifest({ workspace, options }) {
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);
52
+ const adaptationProject = await AppVariant.fromWorkspace(workspace, options.projectNamespace);
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
  }>;