mavensmate
Version:
Core APIs that drive MavensMate IDEs for Salesforce1/Force.com
687 lines (667 loc) • 20.1 kB
JavaScript
/**
* @file Metadata helper classes
* @author Joseph Ferraro <@joeferraro>
*/
'use strict';
var _ = require('lodash');
var fs = require('fs-extra');
var path = require('path');
var util = require('./util');
var logger = require('winston');
// var MavensMateFile = require('./file').MavensMateFile;
var LightningBundle, MetadataHelper;
/**
* Represents an element of Salesforce.com metadata
* @constructor
* @param {Project} project - project instance
* @param {String} path - path to lightning bundle
*/
LightningBundle = function(path, project) {
this.project = project;
this.path = path;
};
// Object.defineProperty(LightningBundle.prototype, 'bundleItems', {
// get: function() {
// var self = this;
// var bundleFiles = [];
// var bfs = fs.readdirSync(self.path);
// _.each(bfs, function(bf) {
// bundleFiles.push(new MavensMateFile({ project: self.project, path: bf }));
// });
// }
// });
Object.defineProperty(LightningBundle.prototype, 'serverContents', {
get: function() {
// TODO
}
});
MetadataHelper = function(opts) {
util.applyProperties(this, opts);
if (this.sfdcClient) {
if (this.sfdcClient.describeCache && this.sfdcClient.describeCache.metadataObjects) {
this.describe = this.sfdcClient.describeCache;
} else {
this.describe = {};
this.describe.metadataObjects = this.parentTypes;
}
} else {
this.describe = {};
this.describe.metadataObjects = this.parentTypes;
}
};
/**
* Attempts to get the metadata type based on the supplied path (could be file path or directory path)
* @param {String} p - /path/to/some/metadata.foo
* @return {Object}
*/
MetadataHelper.prototype.getTypeByPath = function(p) {
var parentPath = path.dirname(p);
var grandparentPath = path.dirname(path.dirname(p));
if (!path.extname(p) && path.basename(parentPath) === 'aura') {
return this.getTypeByDirectoryName('aura');
} else if (path.basename(grandparentPath) === 'aura') {
return this.getTypeByDirectoryName('aura');
} else {
var folderBasedTypes = _.where(this.parentTypes, { 'inFolder': true });
// directory handling
if (!path.extname(p)) {
// foo/bar/src/classes
var directoryMatch = _.find(this.parentTypes, { 'directoryName': path.basename(p) });
if (directoryMatch) {
return this.getTypeByDirectoryName(path.basename(p));
}
//foo/bar/src/reports/myreportfolder
var parentFolderDirectoryMatch = _.find(folderBasedTypes, { 'directoryName': path.basename(parentPath) });
if (parentFolderDirectoryMatch) {
return this.getTypeByDirectoryName(path.basename(parentPath));
}
}
var ext;
if (util.endsWith(p, '-meta.xml')) {
ext = p.replace('-meta.xml', '').split('.').pop();
} else {
ext = p.split('.').pop();
}
var typeBySuffix = this.getTypeBySuffix(ext);
if (typeBySuffix) {
return typeBySuffix;
}
//deeply-nested file handling (report/email template/document)
//foo/bar/src/email/myfolder/foo.email
var grandparentFolderDirectoryMatch = _.find(folderBasedTypes, { 'directoryName': path.basename(grandparentPath) });
if (grandparentFolderDirectoryMatch) {
return this.getTypeByDirectoryName(path.basename(grandparentPath));
}
// email templates, for example, will have a -meta.xml file that holds folder metadata
if (util.endsWith(p, '-meta.xml')) {
return this.getTypeByDirectoryName(path.basename(parentPath));
}
}
};
/**
* Gets metadata type based on the supplied name
* @param {String} name - ApexClass|ApexPage|etc.
* @return {Object}
*/
MetadataHelper.prototype.getTypeByXmlName = function(name) {
var type;
var self = this;
type = _.find(self.describe.metadataObjects, function(metadataType) {
return metadataType.xmlName === name;
});
if (!type) {
type = _.find(self.childTypes, function(childType) {
return childType.xmlName === name;
});
}
if (!type) {
type = _.find(self.parentTypes, function(parentType) {
return parentType.xmlName === name;
});
}
logger.silly('getting metadata type by name: '+name);
logger.silly(type);
return type;
};
/**
* Gets metadata type based on the supplied suffix
* @param {String} suffix - cls|trigger|page|component|etc.
* @return {Object}
*/
MetadataHelper.prototype.getTypeBySuffix = function(suffix) {
var type;
var self = this;
if (suffix.indexOf('.') >= 0) {
suffix = suffix.replace(/\./g, '');
}
_.each(self.describe.metadataObjects, function(metadataType) {
if (metadataType.suffix === suffix) {
type = metadataType;
return false;
}
});
return type;
};
/**
* Gets metadata type based on the supplied directory name
* @param {String} suffix - pages|triggers|classes|etc.
* @return {Object}
*/
MetadataHelper.prototype.getTypeByDirectoryName = function(dirName) {
var type;
var self = this;
_.each(self.describe.metadataObjects, function(metadataType) {
if (metadataType.directoryName === dirName) {
type = metadataType;
return false;
}
});
if (type === undefined) {
_.each(self.parentTypes, function(parentType) {
if (parentType.directoryName === dirName) {
type = parentType;
return false;
}
});
}
return type;
};
MetadataHelper.prototype.childTypes = [
{'xmlName' : 'ActionOverride', 'tagName' : 'actionOverrides', 'parentXmlName' : 'CustomObject' },
{'xmlName' : 'CustomField', 'tagName' : 'fields', 'parentXmlName' : 'CustomObject' },
{'xmlName' : 'BusinessProcess', 'tagName' : 'businessProcesses', 'parentXmlName' : 'CustomObject' },
{'xmlName' : 'RecordType', 'tagName' : 'recordTypes', 'parentXmlName' : 'CustomObject' },
{'xmlName' : 'WebLink', 'tagName' : 'webLinks', 'parentXmlName' : 'CustomObject' },
{'xmlName' : 'ValidationRule', 'tagName' : 'validationRules', 'parentXmlName' : 'CustomObject' },
{'xmlName' : 'NamedFilter', 'tagName' : 'namedFilters', 'parentXmlName' : 'CustomObject' },
{'xmlName' : 'SharingReason', 'tagName' : 'sharingReasons', 'parentXmlName' : 'CustomObject' },
{'xmlName' : 'ListView', 'tagName' : 'listViews', 'parentXmlName' : 'CustomObject' },
{'xmlName' : 'FieldSet', 'tagName' : 'fieldSets', 'parentXmlName' : 'CustomObject' },
{'xmlName' : 'SharingRecalculation', 'tagName' : 'sharingRecalculations', 'parentXmlName' : 'CustomObject' },
{'xmlName' : 'CompactLayout', 'tagName' : 'compactLayouts', 'parentXmlName' : 'CustomObject' },
{'xmlName' : 'CustomLabel', 'tagName' : 'customLabels', 'parentXmlName' : 'CustomLabels' },
{'xmlName' : 'SharingCriteriaRule', 'tagName' : 'sharingCriteriaRules', 'parentXmlName' : 'SharingRules' },
{'xmlName' : 'SharingOwnerRule', 'tagName' : 'sharingOwnerRules', 'parentXmlName' : 'SharingRules' },
{'xmlName' : 'SharingTerritoryRule', 'tagName' : 'sharingTerritoryRules', 'parentXmlName' : 'SharingRules' },
{'xmlName' : 'WorkflowAlert', 'tagName' : 'alerts', 'parentXmlName' : 'Workflow' },
{'xmlName' : 'WorkflowTask', 'tagName' : 'tasks', 'parentXmlName' : 'Workflow' },
{'xmlName' : 'WorkflowOutboundMessage', 'tagName' : 'outboundMessages', 'parentXmlName' : 'Workflow' },
{'xmlName' : 'WorkflowFieldUpdate', 'tagName' : 'fieldUpdates', 'parentXmlName' : 'Workflow' },
{'xmlName' : 'WorkflowRule', 'tagName' : 'rules', 'parentXmlName' : 'Workflow' },
{'xmlName' : 'WorkflowEmailRecipient', 'tagName' : 'emailRecipients', 'parentXmlName' : 'Workflow' },
{'xmlName' : 'WorkflowTimeTrigger', 'tagName' : 'timeTriggers', 'parentXmlName' : 'Workflow' },
{'xmlName' : 'WorkflowActionReference', 'tagName' : 'actionReferences', 'parentXmlName' : 'Workflow' }
];
MetadataHelper.prototype.parentTypes = [
{
'directoryName': 'customMetadata',
'inFolder': false,
'metaFile': false,
'suffix': 'md',
'xmlName': 'CustomMetadata'
},
{
'directoryName': 'installedPackages',
'inFolder': false,
'metaFile': false,
'suffix': 'installedPackage',
'xmlName': 'InstalledPackage'
},
{
'childXmlNames': 'CustomLabel',
'directoryName': 'labels',
'inFolder': false,
'metaFile': false,
'suffix': 'labels',
'xmlName': 'CustomLabels'
},
{
'directoryName': 'staticresources',
'inFolder': false,
'metaFile': true,
'suffix': 'resource',
'xmlName': 'StaticResource'
},
{
'directoryName': 'scontrols',
'inFolder': false,
'metaFile': true,
'suffix': 'scf',
'xmlName': 'Scontrol'
},
{
'directoryName': 'components',
'inFolder': false,
'metaFile': true,
'suffix': 'component',
'xmlName': 'ApexComponent'
},
{
'directoryName': 'pages',
'inFolder': false,
'metaFile': true,
'suffix': 'page',
'xmlName': 'ApexPage'
},
{
'directoryName': 'queues',
'inFolder': false,
'metaFile': false,
'suffix': 'queue',
'xmlName': 'Queue'
},
{
'childXmlNames': [
'CustomField',
'BusinessProcess',
'CompactLayout',
'RecordType',
'WebLink',
'ValidationRule',
'NamedFilter',
'SharingReason',
'ListView',
'FieldSet',
'ApexTriggerCoupling'
],
'directoryName': 'objects',
'inFolder': false,
'metaFile': false,
'suffix': 'object',
'xmlName': 'CustomObject'
},
{
'directoryName': 'reportTypes',
'inFolder': false,
'metaFile': false,
'suffix': 'reportType',
'xmlName': 'ReportType'
},
{
'directoryName': 'reports',
'inFolder': true,
'metaFile': false,
'suffix': 'report',
'xmlName': 'Report'
},
{
'directoryName': 'dashboards',
'inFolder': true,
'metaFile': false,
'suffix': 'dashboard',
'xmlName': 'Dashboard'
},
{
'directoryName': 'analyticSnapshots',
'inFolder': false,
'metaFile': false,
'suffix': 'snapshot',
'xmlName': 'AnalyticSnapshot'
},
{
'directoryName': 'layouts',
'inFolder': false,
'metaFile': false,
'suffix': 'layout',
'xmlName': 'Layout'
},
{
'directoryName': 'portals',
'inFolder': false,
'metaFile': false,
'suffix': 'portal',
'xmlName': 'Portal'
},
{
'directoryName': 'documents',
'inFolder': true,
'metaFile': true,
'xmlName': 'Document'
},
{
'directoryName': 'weblinks',
'inFolder': false,
'metaFile': false,
'suffix': 'weblink',
'xmlName': 'CustomPageWebLink'
},
{
'directoryName': 'quickActions',
'inFolder': false,
'metaFile': false,
'suffix': 'quickAction',
'xmlName': 'QuickAction'
},
{
'childXmlNames': {
'@xsi:nil': 'true'
},
'directoryName': 'flexipages',
'inFolder': false,
'metaFile': false,
'suffix': 'flexipage',
'xmlName': 'FlexiPage'
},
{
'directoryName': 'tabs',
'inFolder': false,
'metaFile': false,
'suffix': 'tab',
'xmlName': 'CustomTab'
},
{
'directoryName': 'customApplicationComponents',
'inFolder': false,
'metaFile': false,
'suffix': 'customApplicationComponent',
'xmlName': 'CustomApplicationComponent'
},
{
'directoryName': 'applications',
'inFolder': false,
'metaFile': false,
'suffix': 'app',
'xmlName': 'CustomApplication'
},
{
'directoryName': 'letterhead',
'inFolder': false,
'metaFile': false,
'suffix': 'letter',
'xmlName': 'Letterhead'
},
{
'directoryName': 'email',
'inFolder': true,
'metaFile': true,
'suffix': 'email',
'xmlName': 'EmailTemplate'
},
{
'childXmlNames': [
'WorkflowFieldUpdate',
'WorkflowKnowledgePublish',
'WorkflowQuickCreate',
'WorkflowTask',
'WorkflowChatterPost',
'WorkflowAlert',
'WorkflowSend',
'WorkflowOutboundMessage',
'WorkflowActionFlow',
'WorkflowApex',
'WorkflowRule'
],
'directoryName': 'workflows',
'inFolder': false,
'metaFile': false,
'suffix': 'workflow',
'xmlName': 'Workflow'
},
{
'childXmlNames': 'AssignmentRule',
'directoryName': 'assignmentRules',
'inFolder': false,
'metaFile': false,
'suffix': 'assignmentRules',
'xmlName': 'AssignmentRules'
},
{
'childXmlNames': 'AutoResponseRule',
'directoryName': 'autoResponseRules',
'inFolder': false,
'metaFile': false,
'suffix': 'autoResponseRules',
'xmlName': 'AutoResponseRules'
},
{
'childXmlNames': 'EscalationRule',
'directoryName': 'escalationRules',
'inFolder': false,
'metaFile': false,
'suffix': 'escalationRules',
'xmlName': 'EscalationRules'
},
{
'directoryName': 'roles',
'inFolder': false,
'metaFile': false,
'suffix': 'role',
'xmlName': 'Role'
},
{
'directoryName': 'groups',
'inFolder': false,
'metaFile': false,
'suffix': 'group',
'xmlName': 'Group'
},
{
'directoryName': 'postTemplates',
'inFolder': false,
'metaFile': false,
'suffix': 'postTemplate',
'xmlName': 'PostTemplate'
},
{
'directoryName': 'approvalProcesses',
'inFolder': false,
'metaFile': false,
'suffix': 'approvalProcess',
'xmlName': 'ApprovalProcess'
},
{
'directoryName': 'homePageComponents',
'inFolder': false,
'metaFile': false,
'suffix': 'homePageComponent',
'xmlName': 'HomePageComponent'
},
{
'directoryName': 'homePageLayouts',
'inFolder': false,
'metaFile': false,
'suffix': 'homePageLayout',
'xmlName': 'HomePageLayout'
},
{
'directoryName': 'objectTranslations',
'inFolder': false,
'metaFile': false,
'suffix': 'objectTranslation',
'xmlName': 'CustomObjectTranslation'
},
{
'directoryName': 'flows',
'inFolder': false,
'metaFile': false,
'suffix': 'flow',
'xmlName': 'Flow'
},
{
'directoryName': 'classes',
'inFolder': false,
'metaFile': true,
'suffix': 'cls',
'xmlName': 'ApexClass'
},
{
'directoryName': 'triggers',
'inFolder': false,
'metaFile': true,
'suffix': 'trigger',
'xmlName': 'ApexTrigger'
},
{
'directoryName': 'profiles',
'inFolder': false,
'metaFile': false,
'suffix': 'profile',
'xmlName': 'Profile'
},
{
'directoryName': 'permissionsets',
'inFolder': false,
'metaFile': false,
'suffix': 'permissionset',
'xmlName': 'PermissionSet'
},
{
'directoryName': 'datacategorygroups',
'inFolder': false,
'metaFile': false,
'suffix': 'datacategorygroup',
'xmlName': 'DataCategoryGroup'
},
{
'directoryName': 'remoteSiteSettings',
'inFolder': false,
'metaFile': false,
'suffix': 'remoteSite',
'xmlName': 'RemoteSiteSetting'
},
{
'directoryName': 'authproviders',
'inFolder': false,
'metaFile': false,
'suffix': 'authprovider',
'xmlName': 'AuthProvider'
},
{
'childXmlNames': [
'LeadOwnerSharingRule',
'LeadCriteriaBasedSharingRule'
],
'directoryName': 'leadSharingRules',
'inFolder': false,
'metaFile': false,
'suffix': 'sharingRules',
'xmlName': 'LeadSharingRules'
},
{
'childXmlNames': [
'CampaignOwnerSharingRule',
'CampaignCriteriaBasedSharingRule'
],
'directoryName': 'campaignSharingRules',
'inFolder': false,
'metaFile': false,
'suffix': 'sharingRules',
'xmlName': 'CampaignSharingRules'
},
{
'childXmlNames': [
'CaseOwnerSharingRule',
'CaseCriteriaBasedSharingRule'
],
'directoryName': 'caseSharingRules',
'inFolder': false,
'metaFile': false,
'suffix': 'sharingRules',
'xmlName': 'CaseSharingRules'
},
{
'childXmlNames': [
'ContactOwnerSharingRule',
'ContactCriteriaBasedSharingRule'
],
'directoryName': 'contactSharingRules',
'inFolder': false,
'metaFile': false,
'suffix': 'sharingRules',
'xmlName': 'ContactSharingRules'
},
{
'childXmlNames': [
'OpportunityOwnerSharingRule',
'OpportunityCriteriaBasedSharingRule'
],
'directoryName': 'opportunitySharingRules',
'inFolder': false,
'metaFile': false,
'suffix': 'sharingRules',
'xmlName': 'OpportunitySharingRules'
},
{
'childXmlNames': [
'AccountOwnerSharingRule',
'AccountCriteriaBasedSharingRule'
],
'directoryName': 'accountSharingRules',
'inFolder': false,
'metaFile': false,
'suffix': 'sharingRules',
'xmlName': 'AccountSharingRules'
},
{
'childXmlNames': [
'CustomObjectOwnerSharingRule',
'CustomObjectCriteriaBasedSharingRule'
],
'directoryName': 'customObjectSharingRules',
'inFolder': false,
'metaFile': false,
'suffix': 'sharingRules',
'xmlName': 'CustomObjectSharingRules'
},
{
'directoryName': 'communities',
'inFolder': false,
'metaFile': false,
'suffix': 'community',
'xmlName': 'Community'
},
{
'directoryName': 'callCenters',
'inFolder': false,
'metaFile': false,
'suffix': 'callCenter',
'xmlName': 'CallCenter'
},
{
'directoryName': 'connectedApps',
'inFolder': false,
'metaFile': false,
'suffix': 'connectedApp',
'xmlName': 'ConnectedApp'
},
{
'directoryName': 'samlssoconfigs',
'inFolder': false,
'metaFile': false,
'suffix': 'samlssoconfig',
'xmlName': 'SamlSsoConfig'
},
{
'directoryName': 'synonymDictionaries',
'inFolder': false,
'metaFile': false,
'suffix': 'synonymDictionary',
'xmlName': 'SynonymDictionary'
},
{
'directoryName': 'settings',
'inFolder': false,
'metaFile': false,
'suffix': 'settings',
'xmlName': 'Settings'
},
{
'directoryName': 'aura',
'inFolder': false,
'metaFile': false,
'xmlName': 'AuraDefinitionBundle'
}
];
MetadataHelper.prototype.inFolderDirectoryNames = function() {
var directoryNames = [];
var self = this;
var parentTypes = (self.describe.metadataObjects && self.describe.metadataObjects.length > 0) ? self.describe.metadataObjects : self.parentTypes;
_.each(parentTypes, function(metadataType) {
if (metadataType.inFolder) {
directoryNames.push(metadataType.directoryName);
}
});
return directoryNames;
};
module.exports.LightningBundle = LightningBundle;
module.exports.MetadataHelper = MetadataHelper;