Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wr/caching #1423

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/client/metadataApiDeploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ export class MetadataApiDeploy extends MetadataTransfer<

public constructor(options: MetadataApiDeployOptions) {
super(options);
options.apiOptions = { ...MetadataApiDeploy.DEFAULT_OPTIONS.apiOptions, ...options.apiOptions };
this.options = Object.assign({}, options);
this.options.apiOptions = { ...MetadataApiDeploy.DEFAULT_OPTIONS.apiOptions, ...options.apiOptions };
this.isRestDeploy = !!options.apiOptions?.rest;
this.registry = options.registry ?? new RegistryAccess();
if (this.mdapiTempDir) {
Expand Down Expand Up @@ -152,7 +152,7 @@ export class MetadataApiDeploy extends MetadataTransfer<
}
const connection = await this.getConnection();
// Recasting to use the project's version of the type
return connection.metadata.checkDeployStatus(this.id, true) as unknown as MetadataApiDeployStatus;
return (await connection.metadata.checkDeployStatus(this.id, true)) as unknown as MetadataApiDeployStatus;
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/client/metadataApiRetrieve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export class RetrieveResult implements MetadataTransferResult {
* @param response The metadata retrieve response from the server
* @param components The ComponentSet of retrieved source components
* @param localComponents The ComponentSet used to create the retrieve request
* @param partialDeleteFileResponses any partially deleted file responses
*/
public constructor(
public readonly response: MetadataApiRetrieveStatus,
Expand Down
2 changes: 1 addition & 1 deletion src/client/metadataTransfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export abstract class MetadataTransfer<
private transferId: Options['id'];
private event = new EventEmitter();
private usernameOrConnection: string | Connection;
private apiVersion?: string;
private readonly apiVersion?: string;

public constructor({ usernameOrConnection, components, apiVersion, id }: Options) {
this.usernameOrConnection = usernameOrConnection;
Expand Down
7 changes: 2 additions & 5 deletions src/convert/metadataConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ export class MetadataConverter {
public static readonly DESTRUCTIVE_CHANGES_POST_XML_FILE = 'destructiveChangesPost.xml';
public static readonly DESTRUCTIVE_CHANGES_PRE_XML_FILE = 'destructiveChangesPre.xml';
public static readonly DEFAULT_PACKAGE_PREFIX = 'metadataPackage';

private registry: RegistryAccess;
private readonly registry: RegistryAccess;

public constructor(registry = new RegistryAccess()) {
this.registry = registry;
Expand All @@ -42,9 +41,7 @@ export class MetadataConverter {
): Promise<ConvertResult> {
try {
const cs = comps instanceof ComponentSet ? comps : new ComponentSet(comps, this.registry);
const components = (
(comps instanceof ComponentSet ? Array.from(comps.getSourceComponents()) : comps) as SourceComponent[]
).filter((comp) => comp.type.isAddressable !== false);
const components = cs.getSourceComponents().filter((comp) => comp.type.isAddressable !== false);

if (output.type !== 'merge' && output.packageName) {
cs.fullName = output.packageName;
Expand Down
16 changes: 7 additions & 9 deletions src/convert/replacements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,7 @@ export const replacementIterations = async (input: string, replacements: MarkedR
const lifecycleInstance = Lifecycle.getInstance();
let output = input;
for (const replacement of replacements) {
// TODO: node 16+ has String.replaceAll for non-regex scenarios
const regex =
typeof replacement.toReplace === 'string' ? new RegExp(replacement.toReplace, 'g') : replacement.toReplace;
const replaced = output.replace(regex, replacement.replaceWith ?? '');
const replaced = output.replaceAll(new RegExp(replacement.toReplace, 'g'), replacement.replaceWith ?? '');

if (replaced !== output) {
output = replaced;
Expand Down Expand Up @@ -117,16 +114,17 @@ class ReplacementMarkingStream extends Transform {
encoding: string,
callback: (err: Error | undefined, data: SourceComponent) => void
): Promise<void> {
const toBeReturned = chunk;
let err: Error | undefined;
// if deleting, or no configs, just pass through
if (!chunk.isMarkedForDelete() && this.replacementConfigs?.length) {
if (!toBeReturned.isMarkedForDelete() && this.replacementConfigs?.length) {
try {
chunk.replacements = await getReplacements(chunk, this.replacementConfigs);
if (chunk.replacements && chunk.parent?.type.strategies?.transformer === 'nonDecomposed') {
toBeReturned.replacements = await getReplacements(toBeReturned, this.replacementConfigs);
if (toBeReturned.replacements && toBeReturned.parent?.type.strategies?.transformer === 'nonDecomposed') {
// Set replacements on the parent of a nonDecomposed CustomLabel as well so that recomposing
// doesn't use the non-replaced content from parent cache.
// See RecompositionFinalizer.recompose() in convertContext.ts
chunk.parent.replacements = chunk.replacements;
toBeReturned.parent.replacements = toBeReturned.replacements;
}
} catch (e) {
if (!(e instanceof Error)) {
Expand All @@ -135,7 +133,7 @@ class ReplacementMarkingStream extends Transform {
err = e;
}
}
callback(err, chunk);
callback(err, toBeReturned);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/convert/streams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export abstract class ComponentWriter extends Writable {
protected rootDestination?: SourcePath;
protected logger: Logger;

public constructor(rootDestination?: SourcePath) {
protected constructor(rootDestination?: SourcePath) {
super({ objectMode: true });
this.rootDestination = rootDestination;
this.logger = Logger.childFromRoot(this.constructor.name);
Expand Down
3 changes: 2 additions & 1 deletion src/convert/transformers/decomposeLabelsTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { SourceComponent } from '../../resolve/sourceComponent';
import { ToSourceFormatInput, WriteInfo } from '../types';
import { JsToXml } from '../streams';
import { unwrapAndOmitNS } from '../../utils/decomposed';
import { META_XML_SUFFIX } from '../../common';
import { DefaultMetadataTransformer } from './defaultMetadataTransformer';

/* Use for the metadata type CustomLabels */
Expand All @@ -31,7 +32,7 @@ export class LabelsMetadataTransformer extends DefaultMetadataTransformer {
output:
// if present in the merge set, use that xml path, otherwise use the default path
mergeSet?.getComponentFilenamesByNameAndType({ fullName: l.fullName, type: labelType.name })?.[0] ??
partiallyAppliedPathCalculator(l.fullName)(`${l.fullName}.label-meta.xml`),
partiallyAppliedPathCalculator(l.fullName)(`${l.fullName}.label${META_XML_SUFFIX}`),
source: new JsToXml({ CustomLabel: l }),
}));
}
Expand Down
4 changes: 2 additions & 2 deletions src/convert/transformers/metadataTransformerFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ Messages.importMessagesDirectory(__dirname);
const messages = Messages.loadMessages('@salesforce/source-deploy-retrieve', 'sdr');

export class MetadataTransformerFactory {
private registry: RegistryAccess;
private context: ConvertContext;
private readonly registry: RegistryAccess;
private readonly context: ConvertContext;

public constructor(registry: RegistryAccess, context = new ConvertContext()) {
this.registry = registry;
Expand Down
2 changes: 1 addition & 1 deletion src/registry/registryAccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Messages.importMessagesDirectory(__dirname);
const messages = Messages.loadMessages('@salesforce/source-deploy-retrieve', 'sdr');

export class RegistryAccess {
private registry: MetadataRegistry;
private readonly registry: MetadataRegistry;
private strictFolderTypes?: MetadataType[];
private folderContentTypes?: MetadataType[];
private aliasTypes?: MetadataType[];
Expand Down
5 changes: 3 additions & 2 deletions src/resolve/adapters/baseSourceAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export abstract class BaseSourceAdapter implements SourceAdapter {
protected parseAsRootMetadataXml(path: SourcePath): MetadataXml | undefined {
const metaXml = this.parseMetadataXml(path);
if (metaXml) {
let isRootMetadataXml = false;
let isRootMetadataXml: boolean;
if (this.type.strictDirectoryName) {
const parentPath = dirname(path);
const typeDirName = basename(this.type.inFolder ? dirname(parentPath) : parentPath);
Expand Down Expand Up @@ -138,6 +138,7 @@ export abstract class BaseSourceAdapter implements SourceAdapter {
*
* @param component Component to populate properties on
* @param trigger Path that `getComponent` was called with
* @param isResolvingSource if you're resolving a local source file
*/
protected abstract populate(
trigger: SourcePath,
Expand All @@ -153,7 +154,7 @@ export abstract class BaseSourceAdapter implements SourceAdapter {
*
* .../tabs/MyTab.tab
*
* @param path File path of a metadata component
* @param type
*/
const parseAsContentMetadataXml =
(type: MetadataType) =>
Expand Down
13 changes: 8 additions & 5 deletions src/resolve/adapters/decomposedSourceAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ export class DecomposedSourceAdapter extends MixedContentSourceAdapter {
isResolvingSource?: boolean
): SourceComponent | undefined {
const metaXml = parseMetadataXml(trigger);
const toBeReturned = component;

if (metaXml?.suffix) {
const pathToContent = this.trimPathToContent(trigger);
const childTypeId = this.type.children?.suffixes?.[metaXml.suffix];
Expand All @@ -92,11 +94,12 @@ export class DecomposedSourceAdapter extends MixedContentSourceAdapter {
triggerIsAChild &&
this.type.children &&
!this.type.children.types[childTypeId].unaddressableWithoutParent &&
// make sure isAddressable is truly set to 'false' not just undefined or omitted
this.type.children.types[childTypeId].isAddressable !== false
) {
if (strategy === 'folderPerType' || strategy === 'topLevel' || isResolvingSource) {
const parent =
component ??
toBeReturned ??
new SourceComponent(
{
name: strategy === 'folderPerType' ? baseName(pathToContent) : pathToContent,
Expand All @@ -117,18 +120,18 @@ export class DecomposedSourceAdapter extends MixedContentSourceAdapter {
this.forceIgnore
);
}
} else if (!component) {
} else if (!toBeReturned) {
// This is most likely metadata found within a CustomObject folder that is not a
// child type of CustomObject. E.g., Layout, SharingRules, ApexClass.
throw new SfError(
messages.getMessage('error_unexpected_child_type', [trigger, this.type.name]),
'TypeInferenceError'
);
}
if (component) {
component.content = pathToContent;
if (toBeReturned) {
toBeReturned.content = pathToContent;
}
}
return component;
return toBeReturned;
}
}
7 changes: 4 additions & 3 deletions src/resolve/adapters/matchingContentSourceAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ export class MatchingContentSourceAdapter extends BaseSourceAdapter {

protected populate(trigger: SourcePath, component: SourceComponent): SourceComponent {
let sourcePath: SourcePath | undefined;
const toBeReturned = component;

if (component.xml === trigger) {
if (toBeReturned.xml === trigger) {
const fsPath = removeMetaXmlSuffix(trigger);
if (this.tree.exists(fsPath)) {
sourcePath = fsPath;
Expand All @@ -58,8 +59,8 @@ export class MatchingContentSourceAdapter extends BaseSourceAdapter {
throw messages.createError('noSourceIgnore', [this.type.name, sourcePath]);
}

component.content = sourcePath;
return component;
toBeReturned.content = sourcePath;
return toBeReturned;
}
}

Expand Down
11 changes: 6 additions & 5 deletions src/resolve/adapters/mixedContentSourceAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,12 @@ export class MixedContentSourceAdapter extends BaseSourceAdapter {
);
}

if (component) {
component.content = contentPath;
let toBeReturned = component;

if (toBeReturned) {
toBeReturned.content = contentPath;
} else {
component = new SourceComponent(
toBeReturned = new SourceComponent(
{
name: baseName(contentPath),
type: this.type,
Expand All @@ -82,7 +84,7 @@ export class MixedContentSourceAdapter extends BaseSourceAdapter {
);
}

return component;
return toBeReturned;
}

/**
Expand All @@ -91,7 +93,6 @@ export class MixedContentSourceAdapter extends BaseSourceAdapter {
* folder will be returned. Intended to be used exclusively for MixedContent types.
*
* @param path Path to trim
* @param type MetadataType to determine content for
*/
protected trimPathToContent(path: SourcePath): SourcePath {
const pathParts = path.split(sep);
Expand Down
4 changes: 2 additions & 2 deletions src/resolve/adapters/sourceAdapterFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ Messages.importMessagesDirectory(__dirname);
const messages = Messages.loadMessages('@salesforce/source-deploy-retrieve', 'sdr');

export class SourceAdapterFactory {
private registry: RegistryAccess;
private tree: TreeContainer;
private readonly registry: RegistryAccess;
private readonly tree: TreeContainer;

public constructor(registry: RegistryAccess, tree: TreeContainer) {
this.registry = registry;
Expand Down
4 changes: 2 additions & 2 deletions src/resolve/connectionResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ export type ResolveConnectionResult = {
* Resolve MetadataComponents from an org connection
*/
export class ConnectionResolver {
private connection: Connection;
private registry: RegistryAccess;
private readonly connection: Connection;
private readonly registry: RegistryAccess;

// Array of metadata type names to use for listMembers. By default it includes
// all types defined in the registry.
Expand Down
29 changes: 23 additions & 6 deletions src/resolve/forceIgnore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { dirname, join, relative } from 'node:path';
import ignore, { Ignore } from 'ignore/index';
import { readFileSync } from 'graceful-fs';
import { Lifecycle } from '@salesforce/core';
import { Lifecycle, Logger } from '@salesforce/core';
import { SourcePath } from '../common/types';
import { searchUp } from '../utils/fileSystemHandler';

Expand All @@ -18,6 +18,7 @@ export class ForceIgnore {
private readonly parser?: Ignore;
private readonly forceIgnoreDirectory?: string;
private DEFAULT_IGNORE = ['**/*.dup', '**/.*', '**/package2-descriptor.json', '**/package2-manifest.json'];
private isPathIgnored = new Map<string, boolean>();

public constructor(forceIgnorePath = '') {
try {
Expand All @@ -42,7 +43,7 @@ export class ForceIgnore {
this.forceIgnoreDirectory = dirname(forceIgnorePath);
}
} catch (e) {
// TODO: log no force ignore
Logger.childFromRoot(this.constructor.name).info('no .forceignore found');
}
}

Expand All @@ -64,19 +65,35 @@ export class ForceIgnore {

public denies(fsPath: SourcePath): boolean {
if (!this.parser || !this.forceIgnoreDirectory) return false;
// we've already figured out if this path is ignored or not, just get it from the cache
if (this.isPathIgnored.has(fsPath)) return this.isPathIgnored.get(fsPath)!;

let result: boolean;
try {
return this.parser.ignores(relative(this.forceIgnoreDirectory, fsPath));
result = this.parser.ignores(relative(this.forceIgnoreDirectory, fsPath));
} catch (e) {
return false;
result = false;
}

this.isPathIgnored.set(fsPath, result);

return result;
}

public accepts(fsPath: SourcePath): boolean {
if (!this.parser || !this.forceIgnoreDirectory) return true;
// we've already figured out if this path is ignored or not, just get it from the cache
// the cache is set for 'denies' so for accept, negate the result
if (this.isPathIgnored.has(fsPath)) return !this.isPathIgnored.get(fsPath);

let result: boolean;
try {
return !this.parser.ignores(relative(this.forceIgnoreDirectory, fsPath));
result = !this.parser.ignores(relative(this.forceIgnoreDirectory, fsPath));
} catch (e) {
return true;
result = true;
}
// since the cache has the 'denies' result, negate the result here
this.isPathIgnored.set(fsPath, !result);
return result;
}
}
4 changes: 1 addition & 3 deletions src/resolve/manifestResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,7 @@ export class ManifestResolver {
numberParseOptions: { leadingZeros: false, hex: false, skipLike: /\.0$/ },
});

const parsedManifest: ParsedPackageManifest = (
parser.parse(validatedContents) as { Package: ParsedPackageManifest }
).Package;
const parsedManifest = (parser.parse(validatedContents) as { Package: ParsedPackageManifest }).Package;

const components = ensureArray(parsedManifest.types)
.map(getValidatedType(manifestPath))
Expand Down
2 changes: 1 addition & 1 deletion src/resolve/metadataResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ const getSuggestionsForUnresolvedTypes =
...guesses.map((guess) =>
messages.getMessage('suggest_type_did_you_mean', [
guess.suffixGuess,
typeof metaSuffix === 'string' || closeMetaSuffix ? '-meta.xml' : '',
typeof metaSuffix === 'string' || closeMetaSuffix ? META_XML_SUFFIX : '',
guess.metadataTypeGuess.name,
])
),
Expand Down
Loading
Loading