sf-metadata
Library for reading, writing and processing (read, update, write) Salesforce metadata files.
Usage
Processor
Read all Salesforce metadata files in a given directory that match a set of patterns. Matched files are passed to a user defined callback function to make changes to the metadata. The processor writes changes back to the original files and returns a list of the filenames that have been updated.
Specification
Using options parameter:
let updatedFiles = await processor({
baseDir: 'baseDir',
patterns: [ 'pattern' ],
processorFunction: (data, filename) => data,
format: 'object'
});
or as a traditional function call:
let updatedFiles = await processor(baseDir, patterns, processorFunction, format);
baseDir
: read all files in this directorypatterns
: match files by glob pattern(s) (note - can be an array of patterns)processorFunction
: synchronous or asynchronous callback function to process metadata
async (data, filename) => {
return data || Promise<data>;
}
format
: (Default: object
) format of the data as passed to the processing function
object
: data is parsed into a JavaScript object (support for XML
and JSON
)string
: data is not parsed, instead the raw contents of the file is passed
Return
: Promise of a list of updated files (all files in the baseDir
that match one or more patterns
). File paths are relative to the baseDir
.
XML parsing uses the excellent xml2js
module, see xml2js NPM docs for data format information.
Glob patterns use the minimatch
module, see minimatch NPM docs for examples.
Note: *.json
files will be interpreted as JSON
. All other files will be interpreted as XML
files (to support the various traditional MD API format .layout
, .object
, etc.).
Be careful not to process files that are not text based - I'm not sure exactly what will happen... definitely nothing good!
Example - Remove enableHistory and enableFeed attribute from object files
let updatedFiles = await processor(
'force-app/main/default',
'**/*.object-meta.xml',
(data, filename) => {
delete data.enableHistory;
delete data.enableFeeds;
}
);
Example - Replace Information labels with Hello in layout files using a string format (i.e. data is not parsed)
let updatedFiles = await processor(
'force-app/main/default',
'**/*.layout-meta.xml',
(data, filename) => data.replace('<label>Information</label>', '<label>Hello</label>'),
'string'
);
This is only an example to demonstrate the difference between object
and string
format - working with a parsed format is obviously better...
Reader
Read all Salesforce metadata files in a given directory that match a set of patterns.
Specification
Using options parameter:
let files = await reader({
baseDir: 'baseDir',
patterns: [ 'pattern' ]
});
or as a traditional function call:
let files = await reader(baseDir, patterns);
baseDir
: read all files in this directorypatterns
: match files by glob pattern(s) (note - can be an array of patterns)
Return
: Promise of a list matched file objects (with methods for reading and writing metadata).
Be careful not to read files that are not text based - I'm not sure exactly what will happen... definitely nothing good!
Example - Get all object files
let files = await reader('force-app/main/default', '**/*.object-meta.xml');
Example - Get all object and layout files
let files = await reader({
baseDir: 'force-app/main/default',
patterns: [ '**/*.layout-meta.xml', '**/*.object-meta.xml' ]
});
Example - Read and write a file
Read file:
let metadata = await file.read();
Example metadata:
{
type: 'xml',
rootKey: 'CustomObject',
data: {
'$': { xmlns: 'http://soap.sforce.com/2006/04/metadata' },
actionOverrides: [
[Object], [Object],
[Object], [Object],
[Object], [Object],
[Object], [Object],
[Object], [Object]
],
allowInChatterGroups: [ 'false' ],
compactLayoutAssignment: [ 'SYSTEM' ],
deploymentStatus: [ 'Deployed' ],
enableActivities: [ 'false' ],
enableBulkApi: [ 'true' ],
enableChangeDataCapture: [ 'false' ],
enableReports: [ 'false' ],
enableSearch: [ 'true' ],
enableSharing: [ 'true' ],
enableStreamingApi: [ 'true' ],
label: [ 'Object Name' ],
nameField: [ [Object] ],
pluralLabel: [ 'Object Names' ],
searchLayouts: [ '' ],
sharingModel: [ 'ReadWrite' ],
visibility: [ 'Public' ]
}
}
Write metadata:
let metadata = await file.write();
Writer
Write a Salesforce metadata file. This is designed to be used to create a new metadata file, see Processor and Reader for modifying existing files.
Specification
Using options parameter:
await writer({
filename: 'filename',
metadata: {
rootKey: 'rootKey',
data: {},
type: 'type'
}
});
or as a traditional function call:
await writer(filename, {
rootKey: 'rootKey',
data: {},
type: 'type'
});
filename
: full file path of file to be writtenmetadata
: metadata object to be built and written to the file
rootKey
: root node - applicable for XML files e.g. CustomObject
data
: metadata that will be built and written to the file, the structure of the data will depend on the typetype
: type of metadata, supported types:
xml
: data must be in xml2js
formatjson
: data must be a standard JavaScript object that will be passed to JSON.stringify
string
: data must be a string and will be written to the file as-is (no building)
Example - Write a text file
await writer('force-app/main/default/myFile.txt', {
data: 'Hello world',
type: 'string'
});
Example - Write a JSON file
await writer('force-app/main/default/myFile.json', {
data: {
property: 'value'
},
type: 'json'
});
Example - Write an XML file
await writer('force-app/main/default/myFile.xml', {
rootKey: 'CustomObject',
data: {
'$': { xmlns: 'http://soap.sforce.com/2006/04/metadata' },
allowInChatterGroups: [ 'false' ],
compactLayoutAssignment: [ 'SYSTEM' ],
deploymentStatus: [ 'Deployed' ],
enableActivities: [ 'false' ],
enableBulkApi: [ 'true' ],
enableChangeDataCapture: [ 'false' ],
enableReports: [ 'false' ],
enableSearch: [ 'true' ],
enableSharing: [ 'true' ],
enableStreamingApi: [ 'true' ],
label: [ 'Object Name' ],
pluralLabel: [ 'Object Names' ],
sharingModel: [ 'ReadWrite' ],
visibility: [ 'Public' ]
},
type: 'xml'
});