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

Port pr v4.1.1 #432

Merged
merged 7 commits into from
Aug 20, 2021
Merged
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
40 changes: 34 additions & 6 deletions src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,43 @@ export {
} from './metadataApiRetrieve';
export { ToolingApi, ToolingDeployOptions, ToolingRetrieveOptions } from './toolingApi';
export {
AsyncResult,
ComponentDeployment,
ComponentRetrieval,
ComponentDiagnostic,
FileResponse,
SourceApiResult,
AsyncResult,
SourceDeployResult,
RequestStatus,
MetadataRequestStatus,
RetrieveFailure,
RetrieveSuccess,
SourceRetrieveResult,
MetadataApiDeployStatus,
DeployDetails,
RunTestResult,
CodeCoverage,
LocationsNotCovered,
CodeCoverageWarnings,
Failures,
Successes,
DeployMessage,
RetrieveRequest,
RetrieveMessage,
FileProperties,
ComponentStatus,
MetadataApiRetrieveStatus,
PackageOption,
PackageOptions,
RetrieveOptions,
SourceDeployResult,
RetrieveMessage,
SourceRetrieveResult,
ContainerAsyncRequest,
ToolingDeployStatus,
ComponentStatus,
FileProperties,
QueryResult,
ApexRecord,
VFRecord,
AuraRecord,
LWCRecord,
ToolingCreateResult,
AuraDefinition,
LightningComponentResource,
} from './types';
5 changes: 4 additions & 1 deletion src/client/metadataApiRetrieve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ export class MetadataApiRetrieve extends MetadataTransfer<
type: 'merge',
mergeWith: this.components.getSourceComponents(),
defaultDirectory: pkg.outputDir,
forceIgnoredPaths: this.components.forceIgnoredPaths ?? new Set<string>(),
}
: {
type: 'directory',
Expand All @@ -229,7 +230,9 @@ export class MetadataApiRetrieve extends MetadataTransfer<
.getSourceComponents()
.toArray();
const convertResult = await converter.convert(zipComponents, 'source', outputConfig);
components.push(...convertResult.converted);
if (convertResult) {
components.push(...convertResult.converted);
}
}
return new ComponentSet(components, registry);
}
Expand Down
4 changes: 4 additions & 0 deletions src/client/metadataTransfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ export abstract class MetadataTransfer<
return result;
} catch (e) {
const error = new MetadataTransferError('md_request_fail', e.message);
if (error.stack && e.stack) {
// append the original stack to this new error
error.stack += `\nDUE TO:\n${e.stack}`;
}
if (this.event.listenerCount('error') === 0) {
throw error;
}
Expand Down
4 changes: 4 additions & 0 deletions src/collections/componentSet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export class ComponentSet extends LazyCollection<MetadataComponent> {
*/
public sourceApiVersion: string;
public fullName?: string;
public forceIgnoredPaths?: Set<string>;
private logger: Logger;
private registry: RegistryAccess;
private components = new Map<string, Map<string, SourceComponent>>();
Expand Down Expand Up @@ -137,6 +138,8 @@ export class ComponentSet extends LazyCollection<MetadataComponent> {
buildComponents(fsPaths, false);
buildComponents(fsDeletePaths, true);

set.forceIgnoredPaths = resolver.forceIgnoredPaths;

return set;
}

Expand Down Expand Up @@ -192,6 +195,7 @@ export class ComponentSet extends LazyCollection<MetadataComponent> {
include: resolveIncludeSet,
registry: options.registry,
});
result.forceIgnoredPaths = components.forceIgnoredPaths;
for (const component of components) {
result.add(component);
}
Expand Down
8 changes: 7 additions & 1 deletion src/collections/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,10 @@
*/
export { LazyCollection } from './lazyCollection';
export { ComponentSet, DeploySetOptions, RetrieveSetOptions } from './componentSet';
export { FromSourceOptions, FromManifestOptions } from './types';
export {
PackageTypeMembers,
PackageManifestObject,
DestructiveChangesType,
FromSourceOptions,
FromManifestOptions,
} from './types';
2 changes: 1 addition & 1 deletion src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
export { SourcePath, OptionalTreeRegistryOptions } from './types';
export { SourcePath, TreeOptions, OptionalTreeRegistryOptions, RegistryOptions } from './types';
export {
DEFAULT_PACKAGE_ROOT_SFDX,
META_XML_SUFFIX,
Expand Down
7 changes: 4 additions & 3 deletions src/convert/convertContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { JsToXml } from './streams';
import { META_XML_SUFFIX, XML_NS_KEY, XML_NS_URL } from '../common';
import { getString, JsonArray, JsonMap } from '@salesforce/ts-types';
import { ComponentSet } from '../collections';
import { normalizeToArray } from '../utils/collections';
import { RecompositionStrategy } from '../registry/types';
import { isEmpty } from '@salesforce/kit';

Expand Down Expand Up @@ -89,7 +90,8 @@ class RecompositionFinalizer extends ConvertTransactionFinalizer<RecompositionSt
parent[groupName] = [];
}

const group = parent[groupName] as JsonArray;
// it might be an object and not an array. Example: custom object with a Field property containing a single field
const group = normalizeToArray(parent[groupName]) as JsonArray;

group.push(childContents);
}
Expand Down Expand Up @@ -306,8 +308,7 @@ class NonDecompositionFinalizer extends ConvertTransactionFinalizer<NonDecomposi
parent[groupName] = [];
}

const group = parent[groupName] as JsonArray;

const group = normalizeToArray(parent[groupName]) as JsonArray;
group.push(child);
}

Expand Down
9 changes: 6 additions & 3 deletions src/convert/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
*/
export { MetadataConverter } from './metadataConverter';
export {
ConvertResult,
ConvertOutputConfig,
SfdxFileFormat,
WriteInfo,
WriterFormat,
DirectoryConfig,
ZipConfig,
MergeConfig,
MetadataTransformer,
SfdxFileFormat,
ConvertOutputConfig,
ConvertResult,
} from './types';
1 change: 1 addition & 0 deletions src/convert/metadataConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ export class MetadataConverter {
mergeSet.add(component.parent ?? component);
}
writer = new StandardWriter(output.defaultDirectory);
writer.forceIgnoredPaths = output.forceIgnoredPaths;
break;
}

Expand Down
20 changes: 17 additions & 3 deletions src/convert/streams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@
*/
import { Archiver, create as createArchive } from 'archiver';
import { createWriteStream } from 'fs';
import { isAbsolute, join } from 'path';
import { basename, dirname, isAbsolute, join } from 'path';
import { pipeline as cbPipeline, Readable, Transform, Writable } from 'stream';
import { promisify } from 'util';
import { SourceComponent, MetadataResolver } from '../resolve';
import { SfdxFileFormat, WriteInfo, WriterFormat } from './types';
import { ensureFileExists } from '../utils/fileSystemHandler';
import { SourcePath, XML_DECL } from '../common';
import { META_XML_SUFFIX, SourcePath, XML_DECL } from '../common';
import { ConvertContext } from './convertContext';
import { MetadataTransformerFactory } from './transformers';
import { JsonMap } from '@salesforce/ts-types';
import { j2xParser } from 'fast-xml-parser';
import { ComponentSet } from '../collections';
import { LibraryError } from '../errors';
import { RegistryAccess } from '../registry';
import { Logger } from '@salesforce/core';
import { fs, Logger } from '@salesforce/core';
export const pipeline = promisify(cbPipeline);

export class ComponentReader extends Readable {
Expand Down Expand Up @@ -126,6 +126,7 @@ export class ComponentConverter extends Transform {
}

export abstract class ComponentWriter extends Writable {
public forceIgnoredPaths?: Set<string> = new Set<string>();
protected rootDestination?: SourcePath;

constructor(rootDestination?: SourcePath) {
Expand Down Expand Up @@ -158,6 +159,19 @@ export class StandardWriter extends ComponentWriter {
const fullDest = isAbsolute(info.output)
? info.output
: join(this.rootDestination, info.output);
if (!fs.fileExistsSync(fullDest)) {
for (const ignoredPath of this.forceIgnoredPaths) {
if (
dirname(ignoredPath).includes(dirname(fullDest)) &&
basename(ignoredPath).includes(basename(fullDest))
) {
return;
}
}
}
if (this.forceIgnoredPaths.has(fullDest)) {
return;
}
// if there are children, resolve each file. o/w just pick one of the files to resolve
if (toResolve.length === 0 || chunk.component.type.children) {
// This is a workaround for a server side ListViews bug where
Expand Down
38 changes: 26 additions & 12 deletions src/convert/transformers/decomposedMetadataTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { SourcePath, META_XML_SUFFIX, XML_NS_URL, XML_NS_KEY } from '../../commo
import { ComponentSet } from '../../collections';
import { DecompositionState } from '../convertContext';
import { DecompositionStrategy } from '../../registry';
import { TypeInferenceError } from '../../errors';

export class DecomposedMetadataTransformer extends BaseMetadataTransformer {
public async toMetadataFormat(component: SourceComponent): Promise<WriteInfo[]> {
Expand All @@ -32,16 +33,10 @@ export class DecomposedMetadataTransformer extends BaseMetadataTransformer {
} else {
const { fullName } = component;
this.context.recomposition.setState((state) => {
if (state[fullName]) {
for (const child of component.getChildren()) {
state[fullName].children.add(child);
}
} else {
state[fullName] = {
component,
children: new ComponentSet(component.getChildren(), this.registry),
};
if (!state[fullName]) {
state[fullName] = { component, children: new ComponentSet([], this.registry) };
}
state[fullName].children = this.ensureValidChildren(component, state[fullName].children);
});
}
// noop since the finalizer will push the writes to the component writer
Expand All @@ -53,11 +48,9 @@ export class DecomposedMetadataTransformer extends BaseMetadataTransformer {
mergeWith?: SourceComponent
): Promise<WriteInfo[]> {
const writeInfos: WriteInfo[] = [];
const childrenOfMergeComponent = mergeWith && this.ensureValidChildren(mergeWith);
const { type, fullName: parentFullName } = component;

const childrenOfMergeComponent = mergeWith
? new ComponentSet(mergeWith.getChildren(), this.registry)
: undefined;
let parentXmlObject: JsonMap;
const composedMetadata = await this.getComposedMetadataEntries(component);

Expand Down Expand Up @@ -147,6 +140,27 @@ export class DecomposedMetadataTransformer extends BaseMetadataTransformer {
return writeInfos;
}

// Ensures that the children of the provided SourceComponent are valid child
// types before adding them to the returned ComponentSet. Invalid child types
// can occur when projects are structured in an atypical way such as having
// ApexClasses or Layouts within a CustomObject folder.
private ensureValidChildren(component: SourceComponent, compSet?: ComponentSet): ComponentSet {
compSet = compSet || new ComponentSet([], this.registry);
const validChildTypes = Object.keys(component.type.children.types);
for (const child of component.getChildren()) {
// Ensure only valid child types are included with the parent.
if (!validChildTypes.includes(child.type?.id)) {
const filePath = child.xml || child.content;
throw new TypeInferenceError('error_unexpected_child_type', [
filePath,
component.type.name,
]);
}
compSet.add(child);
}
return compSet;
}

private async getComposedMetadataEntries(component: SourceComponent): Promise<[string, any][]> {
const composedMetadata = (await component.parseXml())[component.type.name];
return Object.entries(composedMetadata);
Expand Down
6 changes: 4 additions & 2 deletions src/convert/transformers/defaultMetadataTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export class DefaultMetadataTransformer extends BaseMetadataTransformer {
return mergeWith.xml;
}

const { folderContentType, suffix } = component.type;
const { folderContentType, suffix, legacySuffix } = component.type;
let xmlDestination = component.getPackageRelativePath(component.xml, targetFormat);

// quirks:
Expand Down Expand Up @@ -117,7 +117,9 @@ export class DefaultMetadataTransformer extends BaseMetadataTransformer {
);
}
}

if (legacySuffix && suffix && xmlDestination.includes(legacySuffix)) {
xmlDestination = xmlDestination.replace(legacySuffix, suffix);
}
return xmlDestination;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,15 @@ export class StaticResourceMetadataTransformer extends BaseMetadataTransformer {
}

private async getContentType(component: SourceComponent): Promise<string> {
return ((await component.parseXml()).StaticResource as JsonMap).contentType as string;
try {
return ((await component.parseXml()).StaticResource as JsonMap).contentType as string;
} catch (e) {
if ((e as Error).message.includes("Cannot read property 'contentType' of undefined")) {
throw new LibraryError('error_static_resource_missing_resource_file', [
join('staticresources', component.name),
]);
}
}
}

private getExtensionFromType(contentType: string): string {
Expand Down
1 change: 1 addition & 0 deletions src/convert/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export type MergeConfig = {
* Location to store components that aren't merged.
*/
defaultDirectory: SourcePath;
forceIgnoredPaths?: Set<string>;
};

/**
Expand Down
3 changes: 3 additions & 0 deletions src/i18n/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const messages = {
error_convert_invalid_format: "Invalid conversion format '%s'",
error_convert_not_implemented: '%s format conversion not yet implemented for type %s',
error_could_not_infer_type: '%s: Could not infer a metadata type',
error_unexpected_child_type: 'Unexpected child metadata [%s] found for parent type [%s]',
error_expected_source_files: "%s: Expected source files for type '%s'",
error_failed_convert: 'Component conversion failed: %s',
error_merge_metadata_target_unsupported:
Expand Down Expand Up @@ -60,6 +61,8 @@ export const messages = {
error_invalid_package: 'The metadata pacakge was not initialized properly',
error_static_resource_expected_archive_type:
'A StaticResource directory must have a content type of application/zip or application/jar - found %s for %s',
error_static_resource_missing_resource_file:
'A StaticResource must have an associated .resource file, missing %s.resource-meta.xml',
error_no_job_id:
'The %s operation is missing a job ID. Initialize an operation with an ID, or start a new job.',
tapi_deploy_component_limit_error:
Expand Down
Loading