This repository has been archived by the owner on Nov 5, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
aura.ts
263 lines (233 loc) · 9.84 KB
/
aura.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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
import {core, flags, SfdxCommand} from '@salesforce/command';
import {AnyJson} from '@salesforce/ts-types';
import * as chalk from 'chalk';
import fs = require('fs-extra');
import {SobjectResult} from '../../models/sObjectResult';
import {displaylog} from '../../service/displayError';
import {getNameSpacePrefix} from '../../service/getNamespacePrefix';
// Initialize Messages with the current plugin directory
core.Messages.importMessagesDirectory(__dirname);
// Load the specific messages for this file. Messages from @salesforce/command, @salesforce/core,
// or any library that is using the messages framework can also be loaded this way.
const messages = core.Messages.loadMessages('mo-dx-plugin', 'org');
export default class AuraDeploy extends SfdxCommand {
public static description = messages.getMessage('auraDeploy');
public static examples = [
'$ sfdx deploy:aura -p filepath'
];
protected static flagsConfig = {
// flag with a value (-n, --name=VALUE)
filepath: flags.string({ char: 'p', description: 'file path', required: true })
};
// Comment this out if your command does not require an org username
protected static requiresUsername = true;
// Set this to true if your command requires a project workspace; 'requiresProject' is false by default
protected static requiresProject = true;
private startTime: number ;
private endTime: number;
public async run(): Promise<AnyJson> {
this.ux.startSpinner(chalk.bold.yellowBright('Saving'));
this.startTime = new Date().getTime();
const conn = this.org.getConnection();
const namespacePrefix = await getNameSpacePrefix(conn);
const apiVersion = conn.getApiVersion();
interface AuraDefinitionBundle {
DeveloperName: string;
MasterLabel: string;
TableEnumOrId: string;
Description: string;
Id: string;
NamespacePrefix: string;
ApiVersion: number;
}
interface AuraDefinition {
AuraDefinitionBundleId: string;
DefType: string;
Format: string;
Source: string;
Id: string;
}
const _path = this.flags.filepath;
const _lastindex = _path.lastIndexOf('/');
let _fileOrDirName = _path.substring(_lastindex + 1);
let isDirectory: boolean = false;
let validFiles: string[] = []; // Array of all file Names to Save to Server
let fileKey: string []; // This is equivalent to the definitionType
// This is when user provided the directory path
if (_fileOrDirName === _fileOrDirName.split('.')[0]) {
const fileNames = await fs.readdir(_path);
isDirectory = true;
// filter all files without xml
validFiles = fileNames.filter( file => {
if (file.substring(file.lastIndexOf('.') + 1) !== 'xml') {
return file;
}
});
} else {
// Below code when user provided file path and Not directory path
validFiles.push(_fileOrDirName);
_fileOrDirName = _fileOrDirName.split('.')[0];
const validdefTypes = ['Controller', 'Helper', 'Renderer'];
const filterValidTypes = validdefTypes.filter (filetype => _fileOrDirName.lastIndexOf(filetype) > -1 );
if (filterValidTypes.length > 0) {
_fileOrDirName = _fileOrDirName.replace(filterValidTypes[0], '');
}
}
try {
const fileBodyArray = await getFileBodyMap(validFiles);
fileKey = getFileKey(validFiles);
let auraDefinitionBundles = [] as AuraDefinitionBundle[];
auraDefinitionBundles = await getAuraDefinitionBundle(_fileOrDirName) as AuraDefinitionBundle[];
if (auraDefinitionBundles.length === 0) {
const newauraDefinitionBundle = await createAuraDefinitionBundle(_fileOrDirName) as SobjectResult;
if (newauraDefinitionBundle.success) {
const auraDefinitionBundleVar = {} as AuraDefinitionBundle;
auraDefinitionBundleVar.Id = newauraDefinitionBundle.id;
auraDefinitionBundles.push(auraDefinitionBundleVar);
} else {
displaylog(JSON.stringify(newauraDefinitionBundle.errors), this.ux);
displaylog(chalk.bold.redBright('Aura Component Save Failed'), this.ux);
}
}
if (auraDefinitionBundles.length > 0) {
let auraDefinitions = await getAuraDefinitions(auraDefinitionBundles[0].Id) as AuraDefinition[];
auraDefinitions = auraDefinitions.length > 0 ? auraDefinitions : [];
try {
await upsertAuraDefinition(auraDefinitions, fileBodyArray, auraDefinitionBundles[0].Id);
this.endTime = new Date().getTime();
const executionTime = (this.endTime - this.startTime) / 1000;
this.ux.stopSpinner(chalk.bold.greenBright(`AuraBundle Deployed Successfully ✔.Command execution time: ${executionTime} seconds`));
} catch (exception) {
this.ux.stopSpinner(chalk.bold.redBright('Aura Component Save Failed ✖'));
displaylog(exception, this.ux);
}
}
} catch (exception) {
this.ux.stopSpinner(chalk.bold.redBright('Aura Component Save Failed ✖'));
displaylog(exception, this.ux);
}
// function to create AuraDefinitionBundle
async function createAuraDefinitionBundle(name: string) {
const newauraDefinition = {} as AuraDefinitionBundle;
newauraDefinition.DeveloperName = name;
newauraDefinition.MasterLabel = name;
newauraDefinition.Description = 'A Lightning Bundle';
newauraDefinition.ApiVersion = Number(apiVersion);
return conn.tooling.sobject('AuraDefinitionBundle').create(newauraDefinition);
}
// function to get FileKey
function getFileKey(files: string[]) {
return files.map( file => {
return getDefType(file.split('.')[1], file.split('.')[0]);
});
}
// function to get the file body concurrently using Promise.All
async function getFileBodyMap(files: string[]) {
return Promise.all(
files.map(async file => {
const path = isDirectory ? _path + '/' + file : _path;
return await fs.readFile(path , 'utf8');
})
);
}
// There is a bug in the JSforce for bulk inserts so executing insert/updates in loop instead of array
// function to update all the AuraDefinition
async function upsertAuraDefinition(auraDefinitions: AuraDefinition[] , files: string[], bundleId: string) {
// const auraDefinitionsToCreate: AuraDefinition[] = [];
// const auraDefinitionsToUpdate: AuraDefinition[] = [];
const promiseArray = [];
fileKey.forEach ( key => {
const auraDef = auraDefinitions.find(auraDefinition => auraDefinition.DefType === key);
if (auraDef) {
const definitionToUpdate = {} as AuraDefinition;
definitionToUpdate.Id = auraDef.Id;
definitionToUpdate.Source = files[fileKey.indexOf(auraDef.DefType)];
// auraDefinitionsToUpdate.push(definitionToUpdate);
promiseArray.push(conn.tooling.sobject('AuraDefinition').update(definitionToUpdate));
} else {
const definitionToInsert = {} as AuraDefinition;
definitionToInsert.AuraDefinitionBundleId = bundleId;
definitionToInsert.DefType = key;
definitionToInsert.Format = getAuraFormat((validFiles[fileKey.indexOf(key)].split('.'))[1]);
definitionToInsert.Source = files[fileKey.indexOf(key)];
// auraDefinitionsToCreate.push(definitionToInsert);
promiseArray.push(conn.tooling.sobject('AuraDefinition').create(definitionToInsert));
}
});
/*if (auraDefinitionsToUpdate.length > 0) {
promiseArray.push(conn.tooling.sobject('AuraDefinition').update(auraDefinitionsToUpdate));
}
if (auraDefinitionsToCreate.length > 0) {
promiseArray.push(conn.tooling.sobject('AuraDefinition').create(auraDefinitionsToCreate));
}*/
return Promise.all(promiseArray);
}
// function to get AuraDefinitionBundleId
async function getAuraDefinitionBundle(name: string) {
return conn.tooling.sobject('AuraDefinitionBundle').find({
DeveloperName: name,
NamespacePrefix: namespacePrefix
});
}
// function to get AuraDefinition
async function getAuraDefinitions(bundleId: string) {
return conn.tooling.sobject('AuraDefinition').find({
AuraDefinitionBundleId: bundleId
});
}
// function to get file extension
function getDefType(extension: string, filename: string) {
switch (extension) {
case 'app':
// APPLICATION — Lightning Components app
return 'APPLICATION';
case 'cmp':
// COMPONENT — component markup
return 'COMPONENT';
case 'auradoc':
// DOCUMENTATION — documentation markup
return 'DOCUMENTATION';
case 'css':
// STYLE — style (CSS) resource
return 'STYLE';
case 'evt':
// EVENT — event definition
return 'EVENT';
case 'design':
// DESIGN — design definition
return 'DESIGN';
case 'svg':
// SVG — SVG graphic resource
return 'SVG';
case 'js':
const fname = filename.toLowerCase();
if (fname.endsWith('controller')) {
return 'CONTROLLER';
} else if (fname.endsWith('helper')) {
return 'HELPER';
} else if (fname.endsWith('renderer')) {
// RENDERER — client-side renderer
return 'RENDERER';
}
break;
case 'tokens':
return 'TOKENS';
case 'intf':
return 'INTERFACE';
}
}
// get Auraformat
function getAuraFormat(ext: string) {
// is 'js', 'css', or 'xml'
switch (ext) {
case 'js':
return 'JS';
case 'css':
return 'CSS';
default:
return 'XML';
}
}
return '';
}
}