Skip to content

Commit

Permalink
feat: pass in registry
Browse files Browse the repository at this point in the history
  • Loading branch information
mshanemc committed Mar 19, 2024
1 parent b50976c commit 164cca6
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 172 deletions.
6 changes: 4 additions & 2 deletions src/shared/conflicts.ts
Expand Up @@ -5,7 +5,7 @@
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import { resolve } from 'node:path';
import { ComponentSet, ForceIgnore } from '@salesforce/source-deploy-retrieve';
import { ComponentSet, ForceIgnore, RegistryAccess } from '@salesforce/source-deploy-retrieve';
import { ConflictResponse, ChangeResult, SourceConflictError } from './types';
import { getMetadataKey } from './functions';
import { populateTypesAndNames } from './populateTypesAndNames';
Expand Down Expand Up @@ -48,11 +48,13 @@ export const getDedupedConflictsFromChanges = ({
remoteChanges = [],
projectPath,
forceIgnore,
registry,
}: {
localChanges: ChangeResult[];
remoteChanges: ChangeResult[];
projectPath: string;
forceIgnore: ForceIgnore;
registry: RegistryAccess;
}): ChangeResult[] => {
const metadataKeyIndex = new Map(
remoteChanges
Expand All @@ -65,7 +67,7 @@ export const getDedupedConflictsFromChanges = ({

const conflicts = new Set<ChangeResult>();

populateTypesAndNames({ elements: localChanges, excludeUnresolvable: true, projectPath, forceIgnore })
populateTypesAndNames({ excludeUnresolvable: true, projectPath, forceIgnore, registry })(localChanges)
.filter(isChangeResultWithNameAndType)
.map((change) => {
const metadataKey = getMetadataKey(change.name, change.type);
Expand Down
17 changes: 13 additions & 4 deletions src/shared/localComponentSetArray.ts
Expand Up @@ -12,6 +12,7 @@ import {
MetadataResolver,
VirtualTreeContainer,
DestructiveChangesType,
RegistryAccess,
} from '@salesforce/source-deploy-retrieve';
import { sourceComponentGuard } from './guards';
import { supportsPartialDelete, pathIsInFolder } from './functions';
Expand Down Expand Up @@ -51,26 +52,34 @@ const getNonSequential = ({
},
];

export const getComponentSets = (groupings: GroupedFile[], sourceApiVersion?: string): ComponentSet[] => {
export const getComponentSets = ({
groupings,
sourceApiVersion,
registry = new RegistryAccess(),
}: {
groupings: GroupedFile[];
sourceApiVersion?: string;
registry: RegistryAccess;
}): ComponentSet[] => {
const logger = Logger.childFromRoot('localComponentSetArray');

// optimistic resolution...some files may not be possible to resolve
const resolverForNonDeletes = new MetadataResolver();
const resolverForNonDeletes = new MetadataResolver(registry);

return groupings
.map((grouping) => {
logger.debug(
`building componentSet for ${grouping.path} (deletes: ${grouping.deletes.length} nonDeletes: ${grouping.nonDeletes.length})`
);

const componentSet = new ComponentSet();
const componentSet = new ComponentSet(undefined, registry);
if (sourceApiVersion) {
componentSet.sourceApiVersion = sourceApiVersion;
}

// we need virtual components for the deletes.
// TODO: could we use the same for the non-deletes?
const resolverForDeletes = new MetadataResolver(undefined, VirtualTreeContainer.fromFilePaths(grouping.deletes));
const resolverForDeletes = new MetadataResolver(registry, VirtualTreeContainer.fromFilePaths(grouping.deletes));

grouping.deletes
.flatMap((filename) => resolverForDeletes.getComponentsFromPath(filename))
Expand Down
14 changes: 11 additions & 3 deletions src/shared/populateFilePaths.ts
Expand Up @@ -6,7 +6,7 @@
*/
import { EOL } from 'node:os';
import { Logger } from '@salesforce/core';
import { ComponentSet } from '@salesforce/source-deploy-retrieve';
import { ComponentSet, RegistryAccess } from '@salesforce/source-deploy-retrieve';
import { ChangeResult } from './types';
import { isChangeResultWithNameAndType } from './guards';
import {
Expand All @@ -24,7 +24,15 @@ import {
* @param packageDirPaths Array of paths from PackageDirectories
* @returns
*/
export const populateFilePaths = (elements: ChangeResult[], packageDirPaths: string[]): ChangeResult[] => {
export const populateFilePaths = ({
elements,
packageDirPaths,
registry,
}: {
elements: ChangeResult[];
packageDirPaths: string[];
registry: RegistryAccess;
}): ChangeResult[] => {
if (elements.length === 0) {
return [];
}
Expand All @@ -36,7 +44,7 @@ export const populateFilePaths = (elements: ChangeResult[], packageDirPaths: str
.filter(isChangeResultWithNameAndType)
.map(remoteChangeToMetadataMember);

const remoteChangesAsComponentSet = new ComponentSet(remoteChangesAsMetadataMember);
const remoteChangesAsComponentSet = new ComponentSet(remoteChangesAsMetadataMember, registry);

logger.debug(` the generated component set has ${remoteChangesAsComponentSet.size.toString()} items`);
if (remoteChangesAsComponentSet.size < elements.length) {
Expand Down
129 changes: 69 additions & 60 deletions src/shared/populateTypesAndNames.ts
Expand Up @@ -6,7 +6,12 @@
*/
import { Logger } from '@salesforce/core';
import { isString } from '@salesforce/ts-types';
import { MetadataResolver, VirtualTreeContainer, ForceIgnore } from '@salesforce/source-deploy-retrieve';
import {
MetadataResolver,
VirtualTreeContainer,
ForceIgnore,
RegistryAccess,
} from '@salesforce/source-deploy-retrieve';
import { ChangeResult } from './types';
import { isChangeResultWithNameAndType, sourceComponentGuard } from './guards';
import {
Expand All @@ -26,67 +31,71 @@ import {
* @input excludeUnresolvable: boolean Filter out components where you can't get the name and type (that is, it's probably not a valid source component)
* @input resolveDeleted: constructs a virtualTree instead of the actual filesystem--useful when the files no longer exist
*/
export const populateTypesAndNames = ({
elements,
projectPath,
forceIgnore,
excludeUnresolvable = false,
resolveDeleted = false,
}: {
elements: ChangeResult[];
projectPath: string;
forceIgnore?: ForceIgnore;
excludeUnresolvable?: boolean;
resolveDeleted?: boolean;
}): ChangeResult[] => {
if (elements.length === 0) {
return [];
}
const logger = Logger.childFromRoot('SourceTracking.PopulateTypesAndNames');
logger.debug(`populateTypesAndNames for ${elements.length} change elements`);
const filenames = elements.flatMap((element) => element.filenames).filter(isString);
export const populateTypesAndNames =
({
projectPath,
forceIgnore,
excludeUnresolvable = false,
resolveDeleted = false,
registry,
}: {
projectPath: string;
forceIgnore?: ForceIgnore;
excludeUnresolvable?: boolean;
resolveDeleted?: boolean;
registry: RegistryAccess;
}) =>
(elements: ChangeResult[]): ChangeResult[] => {
if (elements.length === 0) {
return [];
}
const logger = Logger.childFromRoot('SourceTracking.PopulateTypesAndNames');
logger.debug(`populateTypesAndNames for ${elements.length} change elements`);
const filenames = elements.flatMap((element) => element.filenames).filter(isString);

// component set generated from the filenames on all local changes
const resolver = new MetadataResolver(
undefined,
resolveDeleted ? VirtualTreeContainer.fromFilePaths(filenames) : undefined,
!!forceIgnore
);
const sourceComponents = filenames
.flatMap((filename) => {
try {
return resolver.getComponentsFromPath(filename);
} catch (e) {
logger.warn(`unable to resolve ${filename}`);
return undefined;
}
})
.filter(sourceComponentGuard);
// component set generated from the filenames on all local changes
const resolver = new MetadataResolver(
registry,
resolveDeleted ? VirtualTreeContainer.fromFilePaths(filenames) : undefined,
!!forceIgnore
);
const sourceComponents = filenames
.flatMap((filename) => {
try {
return resolver.getComponentsFromPath(filename);
} catch (e) {
logger.warn(`unable to resolve ${filename}`);
return undefined;
}
})
.filter(sourceComponentGuard);

logger.debug(` matching SourceComponents have ${sourceComponents.length} items from local`);
logger.debug(` matching SourceComponents have ${sourceComponents.length} items from local`);

const elementMap = new Map(
elements.flatMap((e) => (e.filenames ?? []).map((f) => [ensureRelative(projectPath)(f), e]))
);
const elementMap = new Map(
elements.flatMap((e) => (e.filenames ?? []).map((f) => [ensureRelative(projectPath)(f), e]))
);

// iterates the local components and sets their filenames
sourceComponents.filter(sourceComponentHasFullNameAndType).map((matchingComponent) => {
const filenamesFromMatchingComponent = getAllFiles(matchingComponent);
const ignored = filenamesFromMatchingComponent.filter(excludeLwcLocalOnlyTest).some(forceIgnoreDenies(forceIgnore));
filenamesFromMatchingComponent.map((filename) => {
if (filename && elementMap.has(filename)) {
// add the type/name from the componentSet onto the element
elementMap.set(filename, {
origin: 'remote',
...elementMap.get(filename),
type: matchingComponent.type.name,
name: matchingComponent.fullName,
ignored,
});
}
// iterates the local components and sets their filenames
sourceComponents.filter(sourceComponentHasFullNameAndType).map((matchingComponent) => {
const filenamesFromMatchingComponent = getAllFiles(matchingComponent);
const ignored = filenamesFromMatchingComponent
.filter(excludeLwcLocalOnlyTest)
.some(forceIgnoreDenies(forceIgnore));
filenamesFromMatchingComponent.map((filename) => {
if (filename && elementMap.has(filename)) {
// add the type/name from the componentSet onto the element
elementMap.set(filename, {
origin: 'remote',
...elementMap.get(filename),
type: matchingComponent.type.name,
name: matchingComponent.fullName,
ignored,
});
}
});
});
});
return excludeUnresolvable
? Array.from(new Set(elementMap.values())).filter(isChangeResultWithNameAndType)
: Array.from(new Set(elementMap.values()));
};
return excludeUnresolvable
? Array.from(new Set(elementMap.values())).filter(isChangeResultWithNameAndType)
: Array.from(new Set(elementMap.values()));
};

0 comments on commit 164cca6

Please sign in to comment.