Skip to content

Commit 9df3d5a

Browse files
committed
refactor: isWebAppBundle as shared type guard
1 parent 5881c94 commit 9df3d5a

File tree

2 files changed

+34
-13
lines changed

2 files changed

+34
-13
lines changed

src/client/metadataApiRetrieve.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
import { extract } from './retrieveExtract';
3939
import { getPackageOptions } from './retrieveExtract';
4040
import { MetadataApiRetrieveOptions } from './types';
41+
import { isWebAppBundle } from './utils';
4142

4243
Messages.importMessagesDirectory(__dirname);
4344
const messages = Messages.loadMessages('@salesforce/source-deploy-retrieve', 'sdr');
@@ -101,28 +102,27 @@ export class RetrieveResult implements MetadataTransferResult {
101102

102103
// construct successes
103104
for (const retrievedComponent of this.components.getSourceComponents()) {
104-
const { fullName, type, xml, content } = retrievedComponent;
105+
const { fullName, type, xml } = retrievedComponent;
105106
const baseResponse = {
106107
fullName,
107108
type: type.name,
108109
state: this.localComponents.has(retrievedComponent) ? ComponentStatus.Changed : ComponentStatus.Created,
109110
} as const;
110111

111112
// Special handling for web_app bundles - they need to walk content and report individual files
112-
const isWebAppBundle = type.name === 'DigitalExperienceBundle' && fullName.startsWith('web_app/') && content;
113-
114-
if (isWebAppBundle) {
115-
const walkedPaths = retrievedComponent.walkContent();
113+
if (isWebAppBundle(retrievedComponent)) {
116114
// Add the bundle directory itself
117-
this.fileResponses.push({ ...baseResponse, filePath: content } satisfies FileResponseSuccess);
118-
// Add each file with its specific path
119-
for (const filePath of walkedPaths) {
120-
this.fileResponses.push({ ...baseResponse, filePath } satisfies FileResponseSuccess);
121-
}
115+
this.fileResponses.push(
116+
...[retrievedComponent.content, ...retrievedComponent.walkContent()].map(
117+
(filePath) => ({ ...baseResponse, filePath } satisfies FileResponseSuccess)
118+
)
119+
);
122120
} else if (!type.children || Object.values(type.children.types).some((t) => t.unaddressableWithoutParent)) {
123-
for (const filePath of retrievedComponent.walkContent()) {
124-
this.fileResponses.push({ ...baseResponse, filePath } satisfies FileResponseSuccess);
125-
}
121+
this.fileResponses.push(
122+
...retrievedComponent
123+
.walkContent()
124+
.map((filePath) => ({ ...baseResponse, filePath } satisfies FileResponseSuccess))
125+
);
126126
}
127127

128128
if (xml) {

src/client/utils.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright 2025, Salesforce, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
import { SourceComponent } from '../resolve/sourceComponent';
17+
18+
export const isWebAppBundle = (component: SourceComponent): component is SourceComponent & { content: string } =>
19+
component.type.name === 'DigitalExperienceBundle' &&
20+
component.fullName.startsWith('web_app/') &&
21+
typeof component.content === 'string';

0 commit comments

Comments
 (0)