diff --git a/src/client/metadataApiDeploy.ts b/src/client/metadataApiDeploy.ts index 016e4ccb33..6698272153 100644 --- a/src/client/metadataApiDeploy.ts +++ b/src/client/metadataApiDeploy.ts @@ -272,7 +272,9 @@ export class MetadataApiDeploy extends MetadataTransfer< } catch (err) { const error = err as Error; this.logger.debug( - `Error trying to compile/send deploy telemetry data for deploy ID: ${this.id}\nError: ${error.message}` + `Error trying to compile/send deploy telemetry data for deploy ID: ${this.id ?? ''}\nError: ${ + error.message + }` ); } const deployResult = new DeployResult( @@ -394,7 +396,9 @@ const warnIfUnmatchedServerResult = // warn that this component is found in server response, but not in component set void Lifecycle.getInstance().emitWarning( - `${deployMessage.componentType}, ${deployMessage.fullName}, returned from org, but not found in the local project` + `${deployMessage.componentType ?? ''}, ${ + deployMessage.fullName + }, returned from org, but not found in the local project` ); } }); diff --git a/src/client/metadataTransfer.ts b/src/client/metadataTransfer.ts index 8e1fe25b62..72dd9c693c 100644 --- a/src/client/metadataTransfer.ts +++ b/src/client/metadataTransfer.ts @@ -71,7 +71,7 @@ export abstract class MetadataTransfer< this.canceled = false; const asyncResult = await this.pre(); this.transferId = asyncResult.id; - this.logger.debug(`Started metadata transfer. ID = ${this.id}`); + this.logger.debug(`Started metadata transfer. ID = ${this.id ?? ''}`); return asyncResult; } @@ -105,7 +105,7 @@ export abstract class MetadataTransfer< }); try { - this.logger.debug(`Polling for metadata transfer status. ID = ${this.id}`); + this.logger.debug(`Polling for metadata transfer status. ID = ${this.id ?? ''}`); this.logger.debug(`Polling frequency (ms): ${normalizedOptions.frequency.milliseconds}`); this.logger.debug(`Polling timeout (min): ${normalizedOptions.timeout.minutes}`); const completedMdapiStatus = (await pollingClient.subscribe()) as unknown as Status; diff --git a/src/collections/componentSetBuilder.ts b/src/collections/componentSetBuilder.ts index 42ad48788e..b21dcda1c7 100644 --- a/src/collections/componentSetBuilder.ts +++ b/src/collections/componentSetBuilder.ts @@ -261,8 +261,8 @@ const logComponents = (logger: Logger, componentSet: ComponentSet): void => { .map((m) => logger.debug(m)); if (components.length > 20) logger.debug(`(showing 20 of ${componentSet.size} matches)`); - logger.debug(`ComponentSet apiVersion = ${componentSet.apiVersion}`); - logger.debug(`ComponentSet sourceApiVersion = ${componentSet.sourceApiVersion}`); + logger.debug(`ComponentSet apiVersion = ${componentSet.apiVersion ?? ''}`); + logger.debug(`ComponentSet sourceApiVersion = ${componentSet.sourceApiVersion ?? ''}`); }; const getOrgComponentFilter = ( diff --git a/src/convert/convertContext/nonDecompositionFinalizer.ts b/src/convert/convertContext/nonDecompositionFinalizer.ts index 0a5c4b4700..98edc45785 100644 --- a/src/convert/convertContext/nonDecompositionFinalizer.ts +++ b/src/convert/convertContext/nonDecompositionFinalizer.ts @@ -197,7 +197,7 @@ const recompose = (children: Map, parentSourceComponent: Source const getDefaultOutput = (component: SourceComponent): string => { const { fullName } = component; const [baseName] = fullName.split('.'); - const output = `${baseName}.${component.type.suffix}${META_XML_SUFFIX}`; + const output = `${baseName}.${component.type.suffix ?? ''}${META_XML_SUFFIX}`; return join(component.getPackageRelativePath('', 'source'), output); }; diff --git a/src/convert/convertContext/recompositionFinalizer.ts b/src/convert/convertContext/recompositionFinalizer.ts index e2afb9efb6..4cd2e2b7e7 100644 --- a/src/convert/convertContext/recompositionFinalizer.ts +++ b/src/convert/convertContext/recompositionFinalizer.ts @@ -63,7 +63,7 @@ const stateValueToWriterFormat = source: new JsToXml(await recompose(cache)(stateValue)), output: join( stateValue.component.type.directoryName, - `${stateValue.component.fullName}.${stateValue.component.type.suffix}` + `${stateValue.component.fullName}.${stateValue.component.type.suffix ?? ''}` ), }, ], @@ -139,10 +139,15 @@ const ensureStateValueWithParent = ( return true; } throw new Error( - `The parent component is missing from the recomposition state entry. The children are ${stateValue.children - ?.toArray() - .map((c) => c.fullName) - .join(', ')}` + `The parent component is missing from the recomposition state entry. ${ + stateValue.children + ? `The children are ${stateValue.children + ?.toArray() + .map((c) => c.fullName) + .join(', ')} + ` + : 'There are no children.' + }` ); }; diff --git a/src/convert/transformers/decomposedMetadataTransformer.ts b/src/convert/transformers/decomposedMetadataTransformer.ts index 07184ae897..a3534d69df 100644 --- a/src/convert/transformers/decomposedMetadataTransformer.ts +++ b/src/convert/transformers/decomposedMetadataTransformer.ts @@ -168,7 +168,10 @@ const getChildWriteInfos = return [ { source, - output: join(dirname(mergeWith.xml), `${entryName}.${childComponent.type.suffix}${META_XML_SUFFIX}`), + output: join( + dirname(mergeWith.xml), + `${entryName}.${ensureString(childComponent.type.suffix)}${META_XML_SUFFIX}` + ), }, ]; } @@ -259,7 +262,7 @@ const getDefaultOutput = (component: MetadataComponent): SourcePath => { const childName = tail.length ? tail.join('.') : undefined; const output = join( parent?.type.strategies?.decomposition === DecompositionStrategy.FolderPerType ? type.directoryName : '', - `${childName ?? baseName}.${component.type.suffix}${META_XML_SUFFIX}` + `${childName ?? baseName}.${ensureString(component.type.suffix)}${META_XML_SUFFIX}` ); return join(calculateRelativePath('source')({ self: parent?.type ?? type })(fullName)(baseName), output); }; @@ -289,7 +292,7 @@ type ComposedMetadata = { tagKey: string; tagValue: AnyJson; parentType: Metadat type ComposedMetadataWithChildType = ComposedMetadata & { childType: MetadataType }; type InfoContainer = { - entryName?: string; + entryName: string; childComponent: MetadataComponent; /** the parsed xml */ value: JsonMap; diff --git a/src/convert/transformers/defaultMetadataTransformer.ts b/src/convert/transformers/defaultMetadataTransformer.ts index 7f7d23f598..5865741596 100644 --- a/src/convert/transformers/defaultMetadataTransformer.ts +++ b/src/convert/transformers/defaultMetadataTransformer.ts @@ -101,7 +101,7 @@ const getXmlDestination = ( if (!component.content && !['digitalexperiencebundle'].includes(component.type.id)) { if (targetFormat === 'metadata') { if (folderContentType) { - xmlDestination = xmlDestination.replace(`.${suffix}`, ''); + xmlDestination = xmlDestination.replace(`.${suffix ?? ''}`, ''); } else if (xmlDestination.includes(META_XML_SUFFIX)) { xmlDestination = xmlDestination.slice(0, xmlDestination.lastIndexOf(META_XML_SUFFIX)); } else { @@ -111,7 +111,7 @@ const getXmlDestination = ( } } else { xmlDestination = folderContentType - ? xmlDestination.replace(META_XML_SUFFIX, `.${suffix}${META_XML_SUFFIX}`) + ? xmlDestination.replace(META_XML_SUFFIX, `.${suffix ?? ''}${META_XML_SUFFIX}`) : `${xmlDestination}${META_XML_SUFFIX}`; } } else if (suffix) { diff --git a/src/convert/transformers/staticResourceMetadataTransformer.ts b/src/convert/transformers/staticResourceMetadataTransformer.ts index ab147cb59d..330f4f7491 100644 --- a/src/convert/transformers/staticResourceMetadataTransformer.ts +++ b/src/convert/transformers/staticResourceMetadataTransformer.ts @@ -52,7 +52,8 @@ export class StaticResourceMetadataTransformer extends BaseMetadataTransformer { // Zip the static resource from disk to a stream, compressing at level 9. const zipIt = (): Readable => { - getLogger().debug(`zipping static resource: ${component.content}`); + // static resource should always have content prop + getLogger().debug(`zipping static resource: ${content}`); const zip = JSZip(); // JSZip does not have an API for adding a directory of files recursively so we always @@ -78,7 +79,7 @@ export class StaticResourceMetadataTransformer extends BaseMetadataTransformer { streamFiles: true, }) .on('end', () => { - getLogger().debug(`zip complete for: ${component.content}`); + getLogger().debug(`zip complete for: ${content}`); }) ); }; @@ -88,7 +89,7 @@ export class StaticResourceMetadataTransformer extends BaseMetadataTransformer { source: (await componentIsExpandedArchive(component)) ? zipIt() : getReplacementStreamForReadable(component, content), - output: join(type.directoryName, `${baseName(content)}.${type.suffix}`), + output: join(type.directoryName, `${baseName(content)}.${type.suffix ?? ''}`), }, { source: getReplacementStreamForReadable(component, xml), @@ -197,7 +198,9 @@ const getContentType = async (component: SourceComponent): Promise => { if (typeof output !== 'string') { throw new SfError( - `Expected a string for contentType in ${component.name} (${component.xml}) but got ${JSON.stringify(output)}` + `Expected a string for contentType in ${component.name} (${component.xml ?? ''}) but got ${JSON.stringify( + output + )}` ); } return output; @@ -211,7 +214,7 @@ const getBaseContentPath = (component: SourceComponent, mergeWith?: SourceCompon const baseContentPath = component.getPackageRelativePath(component.content, 'source'); return join(dirname(baseContentPath), baseName(baseContentPath)); } - throw new SfError(`Expected a content path for ${component.name} (${component.xml})`); + throw new SfError(`Expected a content path for ${component.name} (${component.xml ?? ''})`); }; const getExtensionFromType = (contentType: string): string => @@ -238,8 +241,10 @@ async function getStaticResourceZip(component: SourceComponent, content: string) const staticResourceZip = await component.tree.readFile(content); return await JSZip.loadAsync(staticResourceZip, { createFolders: true }); } catch (e) { - throw new SfError(`Unable to open zip file ${content} for ${component.name} (${component.xml})`, 'BadZipFile', [ - 'Check that your file really is a valid zip archive', - ]); + throw new SfError( + `Unable to open zip file ${content} for ${component.name} (${component.xml ?? ''})`, + 'BadZipFile', + ['Check that your file really is a valid zip archive'] + ); } } diff --git a/src/resolve/adapters/digitalExperienceSourceAdapter.ts b/src/resolve/adapters/digitalExperienceSourceAdapter.ts index 785b078584..ce585f9143 100644 --- a/src/resolve/adapters/digitalExperienceSourceAdapter.ts +++ b/src/resolve/adapters/digitalExperienceSourceAdapter.ts @@ -6,6 +6,7 @@ */ import { dirname, join, sep } from 'node:path'; import { Messages } from '@salesforce/core'; +import { ensureString } from '@salesforce/ts-types'; import { META_XML_SUFFIX } from '../../common/constants'; import { SourcePath } from '../../common/types'; import { SourceComponent } from '../sourceComponent'; @@ -147,7 +148,9 @@ export class DigitalExperienceSourceAdapter extends BundleSourceAdapter { // 3 because we want 'digitalExperiences' directory, 'baseType' directory and 'bundleName' directory const basePath = pathParts.slice(0, typeFolderIndex + 3).join(sep); const bundleFileName = pathParts[typeFolderIndex + 2]; - const suffix = this.isBundleType() ? this.type.suffix : this.registry.getParentType(this.type.id)?.suffix; + const suffix = ensureString( + this.isBundleType() ? this.type.suffix : this.registry.getParentType(this.type.id)?.suffix + ); return `${basePath}${sep}${bundleFileName}.${suffix}${META_XML_SUFFIX}`; } diff --git a/src/resolve/connectionResolver.ts b/src/resolve/connectionResolver.ts index 48163bf7e4..be1d6456d1 100644 --- a/src/resolve/connectionResolver.ts +++ b/src/resolve/connectionResolver.ts @@ -112,9 +112,17 @@ export class ConnectionResolver { return { components: Aggregator.filter(componentFilter).map((component) => ({ - fullName: ensureString(component.fullName, `Component fullName was not set for ${component.fileName}`), + fullName: ensureString( + component.fullName, + `Component fullName was not set for ${component.fileName ?? ''}` + ), type: this.registry.getTypeByName( - ensureString(component.type, `Component type was not set for ${component.fullName} (${component.fileName})`) + ensureString( + component.type, + `Component type was not set for ${component.fullName ?? ''} (${ + component.fileName ?? '' + })` + ) ), })), apiVersion: this.connection.getApiVersion(), @@ -142,7 +150,7 @@ const listMembers = return ( standardValueSetRecord.Metadata.standardValue.length && { fullName: standardValueSetRecord.MasterLabel, - fileName: `${mdType.directoryName}/${standardValueSetRecord.MasterLabel}.${mdType.suffix}`, + fileName: `${mdType.directoryName}/${standardValueSetRecord.MasterLabel}.${mdType.suffix ?? ''}`, type: mdType.name, } ); @@ -173,7 +181,7 @@ const inferFilenamesFromType = (metadataType: MetadataType) => (member: RelevantFileProperties): RelevantFileProperties => typeof member.fileName === 'object' - ? { ...member, fileName: `${metadataType.directoryName}/${member.fullName}.${metadataType.suffix}` } + ? { ...member, fileName: `${metadataType.directoryName}/${member.fullName}.${metadataType.suffix ?? ''}` } : member; const isNonEmptyString = (value: string | undefined): boolean => typeof value === 'string' && value.length > 0; diff --git a/src/resolve/sourceComponent.ts b/src/resolve/sourceComponent.ts index 9c4092c57a..f14786430c 100644 --- a/src/resolve/sourceComponent.ts +++ b/src/resolve/sourceComponent.ts @@ -75,7 +75,7 @@ export class SourceComponent implements MetadataComponent { } if (this.parent && this.type.ignoreParentName) { if (!this.name) { - throw new SfError(`Component was initialized without a name: ${this.xml} (${this.type.name})`); + throw new SfError(`Component was initialized without a name: ${this.xml ?? ''} (${this.type.name})`); } return this.name; } else { @@ -355,12 +355,12 @@ export class SourceComponent implements MetadataComponent { if (!uniqueIdElement) { return []; } - const xmlPathToChildren = `${this.type.name}.${childType.xmlElementName}`; + const xmlPathToChildren = `${this.type.name}.${childType.xmlElementName ?? ''}`; const elements = ensureArray(get(parsed, xmlPathToChildren, [])); return elements.map((element) => { const name = getString(element, uniqueIdElement); if (!name) { - throw new SfError(`Missing ${uniqueIdElement} on ${childType.name} in ${this.xml}`); + throw new SfError(`Missing ${uniqueIdElement} on ${childType.name} in ${this.xml ?? ''}`); } return new SourceComponent( { diff --git a/src/utils/filePathGenerator.ts b/src/utils/filePathGenerator.ts index 57275c3f3f..b133a0a73a 100644 --- a/src/utils/filePathGenerator.ts +++ b/src/utils/filePathGenerator.ts @@ -44,7 +44,7 @@ export const filePathsFromMetadataComponent = ( if (type.strategies?.adapter === 'digitalExperience') { // child MD Type, the metafile is a JSON, not an XML - if (type.id === 'digitalexperience') { + if (type.id === 'digitalexperience' && type.metaFileSuffix) { // metafile name = metaFileSuffix for DigitalExperience. return [ join( @@ -55,12 +55,12 @@ export const filePathsFromMetadataComponent = ( } // parent MD Type - if (type.id === 'digitalexperiencebundle') { + if (type.id === 'digitalexperiencebundle' && type.suffix) { return [join(packageDirWithTypeDir, `${fullName}${sep}${basename(fullName)}.${type.suffix}${META_XML_SUFFIX}`)]; } } - if (type.strategies?.adapter === 'decomposed') { + if (type.strategies?.adapter === 'decomposed' && type.suffix) { return [join(packageDirWithTypeDir, `${fullName}${sep}${fullName}.${type.suffix}${META_XML_SUFFIX}`)]; } @@ -70,19 +70,19 @@ export const filePathsFromMetadataComponent = ( } // Non-decomposed parents (i.e., any type that defines children and not a decomposed transformer) - if (type.children) { + if (type.children && type.suffix) { return [join(packageDirWithTypeDir, `${fullName}.${type.suffix}${META_XML_SUFFIX}`)]; } // basic metadata (with or without folders) - if (!type.children && !type.strategies) { + if (!type.children && !type.strategies && type.suffix) { return (type.inFolder ?? type.folderType ? generateFolders({ fullName, type }, packageDirWithTypeDir) : []).concat([ join(packageDirWithTypeDir, `${fullName}.${type.suffix}${META_XML_SUFFIX}`), ]); } // matching content (with or without folders) - if (type.strategies?.adapter === 'matchingContentFile') { + if (type.strategies?.adapter === 'matchingContentFile' && type.suffix) { return (type.inFolder ? generateFolders({ fullName, type }, packageDirWithTypeDir) : []).concat([ join(packageDirWithTypeDir, `${fullName}.${type.suffix}${META_XML_SUFFIX}`), join(packageDirWithTypeDir, `${fullName}.${type.suffix}`), @@ -102,8 +102,10 @@ export const filePathsFromMetadataComponent = ( return [ join( packageDirWithTypeDir, - // registry doesn't have a suffix for EB (it comes down inside the mdapi response) - `${fullName}.${type.strategies?.transformer === 'staticResource' ? type.suffix : 'site'}${META_XML_SUFFIX}` + // registry doesn't have a suffix for EB (it comes down inside the mdapi response). // staticResource has a suffix + `${fullName}.${ + type.strategies?.transformer === 'staticResource' ? (type.suffix as string) : 'site' + }${META_XML_SUFFIX}` ), join(packageDirWithTypeDir, `${fullName}`), ]; @@ -140,7 +142,7 @@ const generateFolders = ({ fullName, type }: MetadataComponent, packageDirWithTy join( packageDirWithTypeDir, `${originalArray.slice(0, index + 1).join(sep)}.${ - registryAccess.getTypeByName(folderType).suffix + registryAccess.getTypeByName(folderType).suffix ?? '' }${META_XML_SUFFIX}` ) ); @@ -159,14 +161,14 @@ const getDecomposedChildType = ({ fullName, type }: MetadataComponent, packageDi // parent join( topLevelTypeDir, - `${fullName.split('.')[0]}${sep}${fullName.split('.')[0]}.${topLevelType.suffix}${META_XML_SUFFIX}` + `${fullName.split('.')[0]}${sep}${fullName.split('.')[0]}.${topLevelType.suffix ?? ''}${META_XML_SUFFIX}` ), // child join( topLevelTypeDir, fullName.split('.')[0], type.directoryName, - `${fullName.split('.')[1]}.${type.suffix}${META_XML_SUFFIX}` + `${fullName.split('.')[1]}.${type.suffix ?? ''}${META_XML_SUFFIX}` ), ]; }; diff --git a/test/snapshot/sampleProjects/customLabels-multiple/snapshots.test.ts b/test/snapshot/sampleProjects/customLabels-multiple/snapshots.test.ts index 6862e46b8d..39a17ebce6 100644 --- a/test/snapshot/sampleProjects/customLabels-multiple/snapshots.test.ts +++ b/test/snapshot/sampleProjects/customLabels-multiple/snapshots.test.ts @@ -53,7 +53,7 @@ describe('Multiple large custom labels files', () => { genUniqueDir: false, }); // Longer than 10 seconds could indicate a regression - expect(Date.now() - convertStartTime, 'conversion should take less than 10 seconds').to.be.lessThan(10000); + expect(Date.now() - convertStartTime, 'conversion should take less than 10 seconds').to.be.lessThan(10_000); const convertedFiles = await getConvertedFilePaths(testOutput); for (const file of convertedFiles) {