-
Notifications
You must be signed in to change notification settings - Fork 102
/
metadataConverter.ts
169 lines (157 loc) · 6.6 KB
/
metadataConverter.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
* Copyright (c) 2020, salesforce.com, inc.
* All rights reserved.
* 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
*/
import { dirname, join, normalize } from 'path';
import { Messages, SfError } from '@salesforce/core';
import { promises } from 'graceful-fs';
import { SourceComponent } from '../resolve';
import { ensureDirectoryExists } from '../utils/fileSystemHandler';
import { SourcePath } from '../common';
import { ComponentSet, DestructiveChangesType } from '../collections';
import { RegistryAccess } from '../registry';
import { ComponentConverter, ComponentReader, pipeline, StandardWriter, ZipWriter } from './streams';
import { ConvertOutputConfig, ConvertResult, DirectoryConfig, SfdxFileFormat, ZipConfig } from './types';
Messages.importMessagesDirectory(__dirname);
const messages = Messages.load('@salesforce/source-deploy-retrieve', 'sdr', [
'error_failed_convert',
'error_merge_metadata_target_unsupported',
]);
export class MetadataConverter {
public static readonly PACKAGE_XML_FILE = 'package.xml';
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;
public constructor(registry = new RegistryAccess()) {
this.registry = registry;
}
public async convert(
comps: ComponentSet | Iterable<SourceComponent>,
targetFormat: SfdxFileFormat,
output: ConvertOutputConfig
): 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);
let manifestContents;
const isSource = targetFormat === 'source';
const tasks: Array<Promise<void>> = [];
let writer: StandardWriter | ZipWriter;
let mergeSet: ComponentSet;
let packagePath: SourcePath;
let defaultDirectory: SourcePath;
switch (output.type) {
case 'directory':
if (output.packageName) {
cs.fullName = output.packageName;
}
manifestContents = await cs.getPackageXml();
packagePath = this.getPackagePath(output);
defaultDirectory = packagePath;
writer = new StandardWriter(packagePath);
if (!isSource) {
const manifestPath = join(packagePath, MetadataConverter.PACKAGE_XML_FILE);
tasks.push(
promises.writeFile(manifestPath, manifestContents),
...cs.getTypesOfDestructiveChanges().map(async (destructiveChangesType) =>
// for each of the destructive changes in the component set, convert and write the correct metadata
// to each manifest
promises.writeFile(
join(packagePath, this.getDestructiveManifest(destructiveChangesType)),
await cs.getPackageXml(4, destructiveChangesType)
)
)
);
}
break;
case 'zip':
if (output.packageName) {
cs.fullName = output.packageName;
}
manifestContents = await cs.getPackageXml();
packagePath = this.getPackagePath(output);
defaultDirectory = packagePath;
writer = new ZipWriter(packagePath);
if (!isSource) {
writer.addToZip(manifestContents, MetadataConverter.PACKAGE_XML_FILE);
// for each of the destructive changes in the component set, convert and write the correct metadata
// to each manifest
for (const destructiveChangeType of cs.getTypesOfDestructiveChanges()) {
writer.addToZip(
await cs.getPackageXml(4, destructiveChangeType),
this.getDestructiveManifest(destructiveChangeType)
);
}
}
break;
case 'merge':
if (!isSource) {
throw new SfError(messages.getMessage('error_merge_metadata_target_unsupported'));
}
defaultDirectory = output.defaultDirectory;
mergeSet = new ComponentSet();
// since child components are composed in metadata format, we need to merge using the parent
for (const component of output.mergeWith) {
mergeSet.add(component.parent ?? component);
}
writer = new StandardWriter(output.defaultDirectory);
writer.forceIgnoredPaths = output.forceIgnoredPaths;
break;
}
const conversionPipeline = pipeline(
new ComponentReader(components),
new ComponentConverter(targetFormat, this.registry, mergeSet, defaultDirectory),
writer
);
await Promise.all([conversionPipeline, ...tasks]);
const result: ConvertResult = { packagePath };
if (output.type === 'zip' && !packagePath) {
result.zipBuffer = (writer as ZipWriter).buffer;
} else if (output.type !== 'zip') {
result.converted = (writer as StandardWriter).converted;
}
return result;
} catch (e) {
throw new SfError(
messages.getMessage('error_failed_convert', [(e as Error).message]),
'ConversionError',
[],
e as Error
);
}
}
private getPackagePath(outputConfig: DirectoryConfig | ZipConfig): SourcePath | undefined {
let packagePath: SourcePath;
const { genUniqueDir = true, outputDirectory, packageName, type } = outputConfig;
if (outputDirectory) {
if (packageName) {
packagePath = join(outputDirectory, packageName);
} else {
if (genUniqueDir) {
packagePath = join(outputDirectory, `${MetadataConverter.DEFAULT_PACKAGE_PREFIX}_${Date.now()}`);
} else {
packagePath = normalize(outputDirectory);
}
}
if (type === 'zip') {
packagePath += '.zip';
ensureDirectoryExists(dirname(packagePath));
} else {
ensureDirectoryExists(packagePath);
}
}
return packagePath;
}
private getDestructiveManifest(destructiveChangesType: DestructiveChangesType): string {
if (destructiveChangesType === DestructiveChangesType.POST) {
return MetadataConverter.DESTRUCTIVE_CHANGES_POST_XML_FILE;
} else if (destructiveChangesType === DestructiveChangesType.PRE) {
return MetadataConverter.DESTRUCTIVE_CHANGES_PRE_XML_FILE;
}
}
}