|
7 | 7 | import { basename, dirname, isAbsolute, normalize, resolve, sep } from 'node:path'; |
8 | 8 | import { defaults, env } from '@salesforce/kit'; |
9 | 9 | import { Dictionary, ensure, JsonMap, Nullable, Optional } from '@salesforce/ts-types'; |
10 | | -import { PackageDir, ProjectJson as ProjectJsonSchema, PackagePackageDir } from '@salesforce/schemas'; |
| 10 | +import { PackageDir, ProjectJson as ProjectJsonSchema, PackagePackageDir, BundleEntry } from '@salesforce/schemas'; |
11 | 11 | import { fs } from './fs/fs'; |
12 | 12 | import { SfdcUrl } from './util/sfdcUrl'; |
13 | 13 | import { ConfigAggregator } from './config/configAggregator'; |
@@ -37,6 +37,7 @@ type NameAndFullPath = { |
37 | 37 |
|
38 | 38 | export type NamedPackagingDir = PackagePackageDir & NameAndFullPath; |
39 | 39 | export type NamedPackageDir = PackageDir & NameAndFullPath; |
| 40 | +export type { BundleEntry }; |
40 | 41 |
|
41 | 42 | export type ProjectJson = ConfigContents & ProjectJsonSchema; |
42 | 43 |
|
@@ -66,7 +67,7 @@ export type ProjectJson = ConfigContents & ProjectJsonSchema; |
66 | 67 | */ |
67 | 68 | export class SfProjectJson extends ConfigFile<ConfigFile.Options, ProjectJson> { |
68 | 69 | /** json properties that are uppercase, or allow uppercase keys inside them */ |
69 | | - public static BLOCKLIST = ['packageAliases', 'plugins']; |
| 70 | + public static BLOCKLIST = ['packageAliases', 'plugins', 'packageBundleAliases']; |
70 | 71 |
|
71 | 72 | public static getFileName(): string { |
72 | 73 | return SFDX_PROJECT_JSON; |
@@ -275,11 +276,18 @@ export class SfProjectJson extends ConfigFile<ConfigFile.Options, ProjectJson> { |
275 | 276 | return this.getContents()?.packageDirectories?.length > 1; |
276 | 277 | } |
277 | 278 |
|
| 279 | + /** |
| 280 | + * Has multiple package bundles defined in the project. |
| 281 | + */ |
| 282 | + public hasMultiplePackageBundles(): boolean { |
| 283 | + return (this.getContents()?.packageBundles?.length ?? 0) > 1; |
| 284 | + } |
| 285 | + |
278 | 286 | /** |
279 | 287 | * Has at least one package alias defined in the project. |
280 | 288 | */ |
281 | | - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type, @typescript-eslint/require-await |
282 | | - public async hasPackageAliases() { |
| 289 | + // eslint-disable-next-line @typescript-eslint/require-await |
| 290 | + public async hasPackageAliases(): Promise<boolean> { |
283 | 291 | return Object.keys(this.getContents().packageAliases ?? {}).length > 0; |
284 | 292 | } |
285 | 293 |
|
@@ -333,6 +341,63 @@ export class SfProjectJson extends ConfigFile<ConfigFile.Options, ProjectJson> { |
333 | 341 | this.set('packageDirectories', modifiedPackagesDirs); |
334 | 342 | } |
335 | 343 |
|
| 344 | + /** |
| 345 | + * Get package bundles defined in the project. |
| 346 | + */ |
| 347 | + public getPackageBundles(): BundleEntry[] { |
| 348 | + return this.get('packageBundles') ?? []; |
| 349 | + } |
| 350 | + /** |
| 351 | + * Add a bundle entry to the project. |
| 352 | + * If the bundle entry already exists, the new entry |
| 353 | + * properties will be merged with the existing properties. |
| 354 | + * |
| 355 | + * @param bundleEntry |
| 356 | + */ |
| 357 | + public addPackageBundle(bundleEntry: BundleEntry): void { |
| 358 | + const bundles = this.getPackageBundles(); |
| 359 | + |
| 360 | + const bundleIndex = bundles.findIndex((b: BundleEntry) => b.name === bundleEntry.name); |
| 361 | + |
| 362 | + const bundleEntryJson: BundleEntry = { |
| 363 | + ...(bundleIndex > -1 ? bundles[bundleIndex] : bundleEntry), |
| 364 | + ...bundleEntry, |
| 365 | + }; |
| 366 | + |
| 367 | + const modifiedBundles = |
| 368 | + bundleIndex > -1 |
| 369 | + ? bundles.map((b: BundleEntry) => (b.name === bundleEntry.name ? bundleEntryJson : b)) |
| 370 | + : [...bundles, bundleEntryJson]; |
| 371 | + |
| 372 | + this.set('packageBundles', modifiedBundles); |
| 373 | + } |
| 374 | + |
| 375 | + /** |
| 376 | + * Has at least one package bundle alias defined in the project. |
| 377 | + */ |
| 378 | + public hasPackageBundleAliases(): boolean { |
| 379 | + return Object.keys(this.getContents().packageBundleAliases ?? {}).length > 0; |
| 380 | + } |
| 381 | + |
| 382 | + /** |
| 383 | + * Get package bundle aliases defined in the project. |
| 384 | + */ |
| 385 | + public getPackageBundleAliases(): Nullable<Dictionary<string>> { |
| 386 | + return this.get('packageBundleAliases') as Nullable<Dictionary<string>>; |
| 387 | + } |
| 388 | + |
| 389 | + /** |
| 390 | + * Add a bundle alias to the project. |
| 391 | + * If the bundle alias already exists, it will be overwritten. |
| 392 | + * |
| 393 | + * @param alias The alias name |
| 394 | + * @param id The bundle ID |
| 395 | + */ |
| 396 | + public addPackageBundleAlias(alias: string, id: string): void { |
| 397 | + const newAliases = { ...(this.get('packageBundleAliases') ?? {}), [alias]: id }; |
| 398 | + this.set('packageBundleAliases', newAliases); |
| 399 | + } |
| 400 | + |
336 | 401 | // keep it because testSetup stubs it! |
337 | 402 | // eslint-disable-next-line class-methods-use-this |
338 | 403 | private doesPackageExist(packagePath: string): boolean { |
@@ -367,6 +432,7 @@ export class SfProject { |
367 | 432 | private packageDirectories?: NamedPackageDir[]; |
368 | 433 | private activePackage: Nullable<NamedPackageDir>; |
369 | 434 | private packageAliases: Nullable<Dictionary<string>>; |
| 435 | + private packageBundleAliases: Nullable<Dictionary<string>>; |
370 | 436 |
|
371 | 437 | /** |
372 | 438 | * Do not directly construct instances of this class -- use {@link SfProject.resolve} instead. |
@@ -619,6 +685,13 @@ export class SfProject { |
619 | 685 | return this.getSfProjectJson().hasMultiplePackages(); |
620 | 686 | } |
621 | 687 |
|
| 688 | + /** |
| 689 | + * Has multiple package bundles defined in the project. |
| 690 | + */ |
| 691 | + public hasMultiplePackageBundles(): boolean { |
| 692 | + return this.getSfProjectJson().hasMultiplePackageBundles(); |
| 693 | + } |
| 694 | + |
622 | 695 | /** |
623 | 696 | * Get the currently activated package on the project. This has no implication on sfdx-project.json |
624 | 697 | * but is useful for keeping track of package and source specific options in a process. |
@@ -734,6 +807,27 @@ export class SfProject { |
734 | 807 | .map(([key]) => key); |
735 | 808 | } |
736 | 809 |
|
| 810 | + public getPackageBundleAliases(): Nullable<Dictionary<string>> { |
| 811 | + if (!this.packageBundleAliases) { |
| 812 | + this.packageBundleAliases = this.getSfProjectJson().getPackageBundleAliases(); |
| 813 | + } |
| 814 | + return this.packageBundleAliases; |
| 815 | + } |
| 816 | + |
| 817 | + public getPackageBundleIdFromAlias(alias: string): Optional<string> { |
| 818 | + const packageBundleAliases = this.getPackageBundleAliases(); |
| 819 | + return packageBundleAliases ? packageBundleAliases[alias] : undefined; |
| 820 | + } |
| 821 | + |
| 822 | + public getAliasesFromPackageBundleId(id: string): string[] { |
| 823 | + if (!/^.{15,18}$/.test(id)) { |
| 824 | + throw messages.createError('invalidId', [id]); |
| 825 | + } |
| 826 | + return Object.entries(this.getPackageBundleAliases() ?? {}) |
| 827 | + .filter(([, value]) => value?.startsWith(id)) |
| 828 | + .map(([key]) => key); |
| 829 | + } |
| 830 | + |
737 | 831 | /** |
738 | 832 | * retrieve the configuration for a named plugin from sfdx-project.json.plugins.pluginName |
739 | 833 | * |
|
0 commit comments