@ds-sfdc/sfparty 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,983 @@
1
+ 'use strict'
2
+
3
+ import path from 'path'
4
+ import fs from 'fs'
5
+ import os from 'os'
6
+ import { readFile } from 'fs'
7
+ import { Parser } from 'xml2js'
8
+ import logUpdate from 'log-update';
9
+ import chalk from 'chalk'
10
+ import convertHrtime from 'convert-hrtime'
11
+ import cliSpinners from 'cli-spinners'
12
+ import * as yaml from 'js-yaml'
13
+ import * as fileUtils from '../fileUtils.js'
14
+ import { profileDefinition } from './definition.js'
15
+
16
+ const spinner = cliSpinners['dots']
17
+ let spinnerFrame = spinner.frames[0]
18
+ let index = 0
19
+
20
+ // TODO replace global logger with error message
21
+ export class Profile {
22
+ #fileName = ''
23
+ #spinnerMessage = ''
24
+ #profileInfo = {
25
+ name: undefined,
26
+ fullName: undefined,
27
+ userLicense: undefined,
28
+ custom: undefined,
29
+ description: undefined,
30
+ }
31
+
32
+ constructor(config) {
33
+ this.sourceDir = config.sourceDir
34
+ this.targetDir = config.targetDir
35
+ this.metaFilePath = config.metaFilePath
36
+ }
37
+
38
+ get metaFilePath() {
39
+ return this._metaFilePath
40
+ }
41
+
42
+ set metaFilePath(value) {
43
+ value = value.trim()
44
+ if (value === '') {
45
+ throw 'The file path cannot be empty'
46
+ }
47
+ this._metaFilePath = value
48
+ this.#fileName = fileUtils.fileInfo(value).filename
49
+ this.#spinnerMessage = `[%1] of ${global.processed.total} - Profile: ${chalk.yellowBright(this.#fileName)}[%2]`
50
+ }
51
+
52
+ split() {
53
+ return new Promise((resolve, reject) => {
54
+ if (!this.#fileName || !this.sourceDir || !this.targetDir || !this.metaFilePath) {
55
+ global.logger.error('Invalid information passed to split')
56
+ process.exit(1)
57
+ }
58
+ if (!fileUtils.fileExists(this.metaFilePath)) {
59
+ global.logger.error(`file not found: ${this.metaFilePath}`)
60
+ process.exit(1)
61
+ }
62
+
63
+ this.profileInfo = fileUtils.fileInfo(this.metaFilePath)
64
+ this.#profileInfo.name = this.profileInfo.filename.replace('.profile-meta.xml', '')
65
+ this.targetDir = path.join(this.targetDir, this.#profileInfo.name)
66
+ let spinnerMessage = this.#spinnerMessage.toString()
67
+ logUpdate(spinnerMessage.toString().replace('[%2]', '').replace('[%1]', global.processed.current.toString().padStart(global.processed.total.toString().length, ' ')))
68
+ let parser = new Parser();
69
+ const getJSON = new Promise((resolve, reject) => {
70
+ readFile(this.metaFilePath, function (err, data) {
71
+ parser.parseString(data, function (err, result) {
72
+ if (result) {
73
+ resolve(result)
74
+ } else {
75
+ global.logger.error(`error converting xml to json: ${filePath}`)
76
+ process.exit(1)
77
+ }
78
+ })
79
+ })
80
+ })
81
+ getJSON.then((result) => {
82
+ resolve(processProfile(result, this.#profileInfo, this.targetDir, this.#spinnerMessage, process.hrtime.bigint()))
83
+ })
84
+ })
85
+
86
+ function processProfile(profileJSON, profileInfo, targetDir, spinnerMessage, startTime) {
87
+ fileUtils.deleteDirectory(targetDir, true) // recursive delete existing directory
88
+ fileUtils.createDirectory(targetDir) // create directory
89
+ let keys = Object.keys(profileJSON.Profile)
90
+
91
+ keys.forEach(key => {
92
+ logUpdate(spinnerMessage.replace('[%2]', `\n${chalk.magentaBright(nextFrame())} ${key}`).replace('[%1]', global.processed.current.toString().padStart(global.processed.total.toString().length, ' ')))
93
+ processKeys: if (profileDefinition.main.includes(key)) {
94
+ profileInfo[key] = profileJSON.Profile[key][0]
95
+ } else if (profileDefinition.directories.includes(key)) {
96
+ fileUtils.createDirectory(path.join(targetDir, key)) // create directory
97
+ switch (key) {
98
+ case 'fieldLevelSecurities':
99
+ fieldLevelSecurities(profileJSON.Profile.fieldLevelSecurities, targetDir)
100
+ break
101
+ case 'fieldPermissions':
102
+ fieldPermissions(profileJSON.Profile.fieldPermissions, targetDir)
103
+ break
104
+ case 'loginFlows':
105
+ loginFlows(profileJSON.Profile.loginFlows, targetDir)
106
+ break
107
+ case 'objectPermissions':
108
+ objectPermissions(profileJSON.Profile.objectPermissions, targetDir)
109
+ break
110
+ case 'recordTypeVisibilities':
111
+ recordTypeVisibilities(profileJSON.Profile.recordTypeVisibilities, targetDir)
112
+ break
113
+ default:
114
+ global.logger.warning('Not processed:', key)
115
+ }
116
+ } else if (profileDefinition.singleFiles.includes(key)) {
117
+ switch (key) {
118
+ case 'applicationVisibilities':
119
+ applicationVisibilities(profileJSON.Profile.applicationVisibilities, targetDir)
120
+ break
121
+ case 'categoryGroupVisibilities':
122
+ categoryGroupVisibilities(profileJSON.Profile.categoryGroupVisibilities, targetDir)
123
+ break
124
+ case 'classAccesses':
125
+ classAccesses(profileJSON.Profile.classAccesses, targetDir)
126
+ break
127
+ case 'customMetadataTypeAccesses':
128
+ customMetadataTypeAccesses(profileJSON.Profile.customMetadataTypeAccesses, targetDir)
129
+ break
130
+ case 'customPermissions':
131
+ customPermissions(profileJSON.Profile.customPermissions, targetDir)
132
+ break
133
+ case 'customSettingAccesses':
134
+ customSettingAccesses(profileJSON.Profile.customSettingAccesses, targetDir)
135
+ break
136
+ case 'externalDataSourceAccesses':
137
+ externalDataSourceAccesses(profileJSON.Profile.externalDataSourceAccesses, targetDir)
138
+ break
139
+ case 'flowAccesses':
140
+ flowAccesses(profileJSON.Profile.flowAccesses, targetDir)
141
+ break
142
+ case 'layoutAssignments':
143
+ layoutAssignments(profileJSON.Profile.layoutAssignments, targetDir)
144
+ break
145
+ case 'loginIpRanges':
146
+ loginIpRanges(profileJSON.Profile.loginIpRanges, targetDir)
147
+ break
148
+ case 'pageAccesses':
149
+ pageAccesses(profileJSON.Profile.pageAccesses, targetDir)
150
+ break
151
+ case 'tabVisibilities':
152
+ tabVisibilities(profileJSON.Profile.tabVisibilities, targetDir)
153
+ break
154
+ case 'userPermissions':
155
+ userPermissions(profileJSON.Profile.userPermissions, targetDir)
156
+ break
157
+ default:
158
+ global.logger.warning('Not processed:', key)
159
+ }
160
+ } else if (profileDefinition.ignore.includes(key)) {
161
+ break processKeys;
162
+ } else {
163
+ global.logger.warning('Not processed:', key)
164
+ }
165
+ })
166
+
167
+ // Main cannot be called until after all the keys are processed and profileJSON.Profile[key][0] is populated
168
+ Main(profileInfo, targetDir, spinnerMessage, startTime)
169
+
170
+ function Main(profileInfo, targetDir, spinnerMessage, startTime) {
171
+ let fileName = path.join(targetDir, `main.${global.format}`)
172
+ saveFile(profileInfo, fileName)
173
+
174
+ const diff = process.hrtime.bigint() - BigInt(startTime)
175
+ let executionTime = convertHrtime(diff);
176
+ executionTime.seconds = Math.round(executionTime.seconds)
177
+ executionTime.milliseconds = Math.round(executionTime.milliseconds / 1000)
178
+ if (executionTime.milliseconds == 0 && executionTime.nanoseconds > 0) executionTime.milliseconds = 1
179
+ let durationMessage = `${executionTime.seconds}.${executionTime.milliseconds}s`
180
+ logUpdate(spinnerMessage.replace('[%2]', `. ${chalk.greenBright('✔')} Processed in ${durationMessage}.`).replace('[%1]', global.processed.current.toString().padStart(global.processed.total.toString().length, ' ')))
181
+ logUpdate.done()
182
+ }
183
+
184
+ function applicationVisibilities(jsonResult, targetDir) {
185
+ let json = {
186
+ applicationVisibilities: undefined
187
+ }
188
+
189
+ // sort json to order by field
190
+ jsonResult.sort((a, b) => {
191
+ if (a.application < b.application) {
192
+ return -1;
193
+ }
194
+ if (a.application > b.application) {
195
+ return 1;
196
+ }
197
+ return 0;
198
+ })
199
+ json.applicationVisibilities = jsonResult
200
+ let fileName = path.join(targetDir, 'applicationVisibilities' + `.${global.format}`)
201
+ saveFile(json, fileName)
202
+ }
203
+
204
+ function categoryGroupVisibilities(jsonResult) {
205
+ let json = {
206
+ categoryGroupVisibilities: undefined
207
+ }
208
+
209
+ // sort json to order by field
210
+ jsonResult.sort((a, b) => {
211
+ if (a.dataCategoryGroup < b.dataCategoryGroup) {
212
+ return -1;
213
+ }
214
+ if (a.dataCategoryGroup > b.dataCategoryGroup) {
215
+ return 1;
216
+ }
217
+ return 0;
218
+ })
219
+
220
+ // sort json keys to put field first
221
+ jsonResult.forEach(function (part, index) {
222
+ this[index].dataCategoryGroup = this[index].dataCategoryGroup[0]
223
+ this[index].visibility = this[index].visibility[0]
224
+ this[index] = Object.keys(this[index])
225
+ .sort((a, b) => {
226
+ if (a == 'dataCategoryGroup') return -1
227
+ if (b == 'dataCategoryGroup') return 1
228
+ if (a == 'visibility') return -1
229
+ if (b == 'visibility') return 1
230
+ if (a == 'dataCategories') return -1
231
+ if (b == 'dataCategories') return 1
232
+
233
+ return 0;
234
+ })
235
+ .reduce((accumulator, key) => {
236
+ accumulator[key] = this[index][key];
237
+
238
+ return accumulator;
239
+ }, {});
240
+ }, jsonResult);
241
+
242
+ json.categoryGroupVisibilities = jsonResult
243
+ let fileName = path.join(targetDir, 'categoryGroupVisibilities' + `.${global.format}`)
244
+ saveFile(json, fileName)
245
+ }
246
+
247
+ function classAccesses(jsonResult, targetDir) {
248
+ let json = {
249
+ classAccesses: undefined
250
+ }
251
+
252
+ // sort json to order by field
253
+ jsonResult.sort((a, b) => {
254
+ if (a.apexClass < b.apexClass) {
255
+ return -1;
256
+ }
257
+ if (a.apexClass > b.apexClass) {
258
+ return 1;
259
+ }
260
+ return 0;
261
+ })
262
+ json.classAccesses = jsonResult
263
+ let fileName = path.join(targetDir, 'classAccesses' + `.${global.format}`)
264
+ saveFile(json, fileName)
265
+ }
266
+
267
+ function customMetadataTypeAccesses(jsonResult, targetDir) {
268
+ let json = {
269
+ customMetadataTypeAccesses: undefined
270
+ }
271
+
272
+ // sort json keys to put field first
273
+ jsonResult.forEach(function (part, index) {
274
+ this[index] = Object.keys(this[index])
275
+ .sort((a, b) => {
276
+ if (a == 'name') return -1
277
+ if (b == 'name') return 1
278
+ if (a == 'enabled') return -1
279
+ if (b == 'enabled') return 1
280
+
281
+ return 0;
282
+ })
283
+ .reduce((accumulator, key) => {
284
+ accumulator[key] = this[index][key];
285
+
286
+ return accumulator;
287
+ }, {});
288
+ }, jsonResult);
289
+
290
+ // sort json to order by name
291
+ jsonResult.sort((a, b) => {
292
+ if (a.name < b.name) {
293
+ return -1;
294
+ }
295
+ if (a.name > b.name) {
296
+ return 1;
297
+ }
298
+ return 0;
299
+ })
300
+ json.customMetadataTypeAccesses = jsonResult
301
+ let fileName = path.join(targetDir, 'customMetadataTypeAccesses' + `.${global.format}`)
302
+ saveFile(json, fileName)
303
+ }
304
+
305
+ function customPermissions(jsonResult, targetDir) {
306
+ let json = {
307
+ customPermissions: undefined
308
+ }
309
+
310
+ // sort json keys to put field first
311
+ jsonResult.forEach(function (part, index) {
312
+ this[index] = Object.keys(this[index])
313
+ .sort((a, b) => {
314
+ if (a == 'name') return -1
315
+ if (b == 'name') return 1
316
+ if (a == 'enabled') return -1
317
+ if (b == 'enabled') return 1
318
+
319
+ return 0;
320
+ })
321
+ .reduce((accumulator, key) => {
322
+ accumulator[key] = this[index][key];
323
+
324
+ return accumulator;
325
+ }, {});
326
+ }, jsonResult);
327
+
328
+ // sort json to order by name
329
+ jsonResult.sort((a, b) => {
330
+ if (a.name < b.name) {
331
+ return -1;
332
+ }
333
+ if (a.name > b.name) {
334
+ return 1;
335
+ }
336
+ return 0;
337
+ })
338
+ json.customPermissions = jsonResult
339
+ let fileName = path.join(targetDir, 'customPermissions' + `.${global.format}`)
340
+ saveFile(json, fileName)
341
+ }
342
+
343
+ function customSettingAccesses(jsonResult, targetDir) {
344
+ let json = {
345
+ customSettingAccesses: undefined
346
+ }
347
+
348
+ // sort json keys to put field first
349
+ jsonResult.forEach(function (part, index) {
350
+ this[index] = Object.keys(this[index])
351
+ .sort((a, b) => {
352
+ if (a == 'name') return -1
353
+ if (b == 'name') return 1
354
+ if (a == 'enabled') return -1
355
+ if (b == 'enabled') return 1
356
+
357
+ return 0;
358
+ })
359
+ .reduce((accumulator, key) => {
360
+ accumulator[key] = this[index][key];
361
+
362
+ return accumulator;
363
+ }, {});
364
+ }, jsonResult);
365
+
366
+ // sort json to order by name
367
+ jsonResult.sort((a, b) => {
368
+ if (a.name < b.name) {
369
+ return -1;
370
+ }
371
+ if (a.name > b.name) {
372
+ return 1;
373
+ }
374
+ return 0;
375
+ })
376
+ json.customSettingAccesses = jsonResult
377
+ let fileName = path.join(targetDir, 'customSettingAccesses' + `.${global.format}`)
378
+ saveFile(json, fileName)
379
+ }
380
+
381
+ function externalDataSourceAccesses(jsonResult, targetDir) {
382
+ let json = {
383
+ externalDataSourceAccesses: undefined
384
+ }
385
+
386
+ // sort json keys to put field first
387
+ jsonResult.forEach(function (part, index) {
388
+ this[index] = Object.keys(this[index])
389
+ .sort((a, b) => {
390
+ if (a == 'externalDataSource') return -1
391
+ if (b == 'externalDataSource') return 1
392
+ if (a == 'enabled') return -1
393
+ if (b == 'enabled') return 1
394
+
395
+ return 0;
396
+ })
397
+ .reduce((accumulator, key) => {
398
+ accumulator[key] = this[index][key];
399
+
400
+ return accumulator;
401
+ }, {});
402
+ }, jsonResult);
403
+
404
+ // sort json to order by externalDataSource
405
+ jsonResult.sort((a, b) => {
406
+ if (a.externalDataSource < b.externalDataSource) {
407
+ return -1;
408
+ }
409
+ if (a.externalDataSource > b.externalDataSource) {
410
+ return 1;
411
+ }
412
+ return 0;
413
+ })
414
+ json.externalDataSourceAccesses = jsonResult
415
+ let fileName = path.join(targetDir, 'externalDataSourceAccesses' + `.${global.format}`)
416
+ saveFile(json, fileName)
417
+ }
418
+
419
+ function fieldLevelSecurities(jsonResult, targetDir) {
420
+ const objects = {}
421
+
422
+ // populate objects with fieldLevelSecurities data per object
423
+ jsonResult.forEach(element => {
424
+ let [object] = element.field[0].toString().replaceAll('\n', '').trim().split('.')
425
+ if (objects[object] === undefined) {
426
+ objects[object] = []
427
+ }
428
+ objects[object].push(element)
429
+ })
430
+
431
+ // iterate objects keys (per object)
432
+ let keys = Object.keys(objects)
433
+ keys.forEach(key => {
434
+ let tag = 'fieldLevelSecurities'
435
+ let fileName = path.join(targetDir, tag, key + `.${global.format}`)
436
+
437
+ // sort json keys to put field first
438
+ let jsonResult = objects[key]
439
+ jsonResult.forEach(function (part, index) {
440
+ this[index] = Object.keys(this[index])
441
+ .sort((a, b) => {
442
+ if (a == 'field') return -1
443
+ if (b == 'field') return 1
444
+ if (a == 'editable') return -1
445
+ if (b == 'editable') return 1
446
+ if (a == 'readable') return -1
447
+ if (b == 'readable') return 1
448
+ if (a == 'hidden') return -1
449
+ if (b == 'hidden') return 1
450
+
451
+ return 0;
452
+ })
453
+ .reduce((accumulator, key) => {
454
+ accumulator[key] = this[index][key];
455
+
456
+ return accumulator;
457
+ }, {});
458
+ }, jsonResult);
459
+
460
+ // sort json to order by field
461
+ jsonResult.sort((a, b) => {
462
+ if (a.field < b.field) {
463
+ return -1;
464
+ }
465
+ if (a.field > b.field) {
466
+ return 1;
467
+ }
468
+ return 0;
469
+ })
470
+
471
+ let json = {
472
+ object: undefined,
473
+ fieldLevelSecurities: undefined
474
+ }
475
+
476
+ json.object = key
477
+ json.fieldLevelSecurities = jsonResult
478
+ saveFile(json, fileName)
479
+ })
480
+ }
481
+
482
+ function fieldPermissions(jsonResult, targetDir) {
483
+ const objects = {}
484
+
485
+ // populate objects with fieldPermission data per object
486
+ jsonResult.forEach(element => {
487
+ let [object] = element.field[0].toString().replaceAll('\n', '').trim().split('.')
488
+ if (objects[object] === undefined) {
489
+ objects[object] = []
490
+ }
491
+ objects[object].push(element)
492
+ })
493
+
494
+ // iterate objects keys (per object)
495
+ let keys = Object.keys(objects)
496
+ keys.forEach(key => {
497
+ let tag = 'fieldPermissions'
498
+ let fileName = path.join(targetDir, tag, key + `.${global.format}`)
499
+
500
+ // sort json keys to put field first
501
+ let jsonResult = objects[key]
502
+ jsonResult.forEach(function (part, index) {
503
+ this[index] = Object.keys(this[index])
504
+ .sort((a, b) => {
505
+ if (a == 'field') return -1
506
+ if (b == 'field') return 1
507
+ if (a == 'editable') return -1
508
+ if (b == 'editable') return 1
509
+ if (a == 'readable') return -1
510
+ if (b == 'readable') return 1
511
+ if (a == 'hidden') return -1
512
+ if (b == 'hidden') return 1
513
+
514
+ return 0;
515
+ })
516
+ .reduce((accumulator, key) => {
517
+ accumulator[key] = this[index][key];
518
+
519
+ return accumulator;
520
+ }, {});
521
+ }, jsonResult);
522
+
523
+ // sort json to order by field
524
+ jsonResult.sort((a, b) => {
525
+ if (a.field < b.field) {
526
+ return -1;
527
+ }
528
+ if (a.field > b.field) {
529
+ return 1;
530
+ }
531
+ return 0;
532
+ })
533
+
534
+ let json = {
535
+ object: undefined,
536
+ fieldPermissions: undefined
537
+ }
538
+
539
+ json.object = key
540
+ json.fieldPermissions = jsonResult
541
+ saveFile(json, fileName)
542
+ })
543
+ }
544
+
545
+ function flowAccesses(jsonResult, targetDir) {
546
+ let json = {
547
+ flowAccesses: undefined
548
+ }
549
+
550
+ // sort json keys to put field first
551
+ jsonResult.forEach(function (part, index) {
552
+ this[index] = Object.keys(this[index])
553
+ .sort((a, b) => {
554
+ if (a == 'flow') return -1
555
+ if (b == 'flow') return 1
556
+ if (a == 'enabled') return -1
557
+ if (b == 'enabled') return 1
558
+
559
+ return 0;
560
+ })
561
+ .reduce((accumulator, key) => {
562
+ accumulator[key] = this[index][key];
563
+
564
+ return accumulator;
565
+ }, {});
566
+ }, jsonResult);
567
+
568
+ // sort json to order by flow
569
+ jsonResult.sort((a, b) => {
570
+ if (a.flow < b.flow) {
571
+ return -1;
572
+ }
573
+ if (a.flow > b.flow) {
574
+ return 1;
575
+ }
576
+ return 0;
577
+ })
578
+ json.flowAccesses = jsonResult
579
+ let fileName = path.join(targetDir, 'flowAccesses' + `.${global.format}`)
580
+ saveFile(json, fileName)
581
+ }
582
+
583
+ function layoutAssignments(jsonResult, targetDir) {
584
+ let json = {
585
+ layoutAssignments: undefined
586
+ }
587
+
588
+ // sort json keys to put field first
589
+ jsonResult.forEach(function (part, index) {
590
+ this[index] = Object.keys(this[index])
591
+ .sort((a, b) => {
592
+ if (a == 'layout') return -1
593
+ if (b == 'layout') return 1
594
+ if (a == 'recordType') return -1
595
+ if (b == 'recordType') return 1
596
+
597
+ return 0;
598
+ })
599
+ .reduce((accumulator, key) => {
600
+ accumulator[key] = this[index][key];
601
+
602
+ return accumulator;
603
+ }, {});
604
+ }, jsonResult);
605
+
606
+ // sort json to order by layout
607
+ jsonResult.sort((a, b) => {
608
+ if (a.layout < b.layout) {
609
+ return -1;
610
+ }
611
+ if (a.layout > b.layout) {
612
+ return 1;
613
+ }
614
+ if (a.recordType < b.recordType || a.recordType === undefined) {
615
+ return -1;
616
+ }
617
+ if (a.recordType > b.recordType || b.recordType === undefined) {
618
+ return 1;
619
+ }
620
+ return 0;
621
+ })
622
+ json.layoutAssignments = jsonResult
623
+ let fileName = path.join(targetDir, 'layoutAssignments' + `.${global.format}`)
624
+ saveFile(json, fileName)
625
+ }
626
+
627
+ function loginFlows(jsonResult, targetDir) {
628
+ const flows = {}
629
+
630
+ // populate objects with fieldPermission data per object
631
+ jsonResult.forEach(element => {
632
+ let [flow] = element.friendlyName
633
+ flows[flow] = []
634
+ flows[flow].push(element)
635
+ })
636
+
637
+ // iterate flows keys (per object)
638
+ let keys = Object.keys(flows)
639
+ keys.forEach(key => {
640
+ let tag = 'loginFlows'
641
+ let fileName = path.join(targetDir, tag, key + `.${global.format}`)
642
+
643
+ // sort json keys to put field first
644
+ let jsonResult = flows[key]
645
+ jsonResult.forEach(function (part, index) {
646
+ this[index] = Object.keys(this[index])
647
+ .sort((a, b) => {
648
+ if (a == 'friendlyName') return -1
649
+ if (b == 'friendlyName') return 1
650
+ if (a == 'flow') return -1
651
+ if (b == 'flow') return 1
652
+ if (a == 'flowType') return -1
653
+ if (b == 'flowType') return 1
654
+ if (a == 'uiLoginFlowType') return -1
655
+ if (b == 'uiLoginFlowType') return 1
656
+ if (a == 'useLightningRuntime') return -1
657
+ if (b == 'useLightningRuntime') return 1
658
+ if (a == 'vfFlowPage') return -1
659
+ if (b == 'vfFlowPage') return 1
660
+ if (a == 'vfFlowPageTitle') return -1
661
+ if (b == 'vfFlowPageTitle') return 1
662
+
663
+ return 0;
664
+ })
665
+ .reduce((accumulator, key) => {
666
+ accumulator[key] = this[index][key];
667
+
668
+ return accumulator;
669
+ }, {});
670
+ }, jsonResult);
671
+
672
+ let json = {
673
+ flow: undefined,
674
+ }
675
+
676
+ json.loginFlows = jsonResult
677
+ saveFile(json, fileName)
678
+ })
679
+ }
680
+
681
+ // TODO loginHours
682
+
683
+ function loginIpRanges(jsonResult, targetDir) {
684
+ let json = {
685
+ loginIpRanges: undefined
686
+ }
687
+
688
+ // sort json keys to put field first
689
+ jsonResult.forEach(function (part, index) {
690
+ this[index] = Object.keys(this[index])
691
+ .sort((a, b) => {
692
+ if (a == 'startAddress') return -1
693
+ if (b == 'startAddress') return 1
694
+ if (a == 'endAddress') return -1
695
+ if (b == 'endAddress') return 1
696
+ if (a == 'description') return -1
697
+ if (b == 'description') return 1
698
+
699
+ return 0;
700
+ })
701
+ .reduce((accumulator, key) => {
702
+ accumulator[key] = this[index][key];
703
+
704
+ return accumulator;
705
+ }, {});
706
+ }, jsonResult);
707
+
708
+ // sort json to order by startAddress
709
+ jsonResult.sort((a, b) => {
710
+ if (a.startAddress < b.startAddress) {
711
+ return -1;
712
+ }
713
+ if (a.startAddress > b.startAddress) {
714
+ return 1;
715
+ }
716
+ return 0;
717
+ })
718
+ json.loginIpRanges = jsonResult
719
+ let fileName = path.join(targetDir, 'loginIpRanges' + `.${global.format}`)
720
+ saveFile(json, fileName)
721
+ }
722
+
723
+ function objectPermissions(jsonResult, targetDir) {
724
+ const objects = {}
725
+
726
+ // populate objects with fieldPermission data per object
727
+ jsonResult.forEach(element => {
728
+ let [object] = element.object
729
+ if (objects[object] === undefined) {
730
+ objects[object] = []
731
+ }
732
+ objects[object].push(element)
733
+ })
734
+
735
+ // iterate objects keys (per object)
736
+ let keys = Object.keys(objects)
737
+ keys.forEach(key => {
738
+ let tag = 'objectPermissions'
739
+ let fileName = path.join(targetDir, tag, key + `.${global.format}`)
740
+
741
+ // sort json keys
742
+ let jsonResult = objects[key]
743
+ delete jsonResult[0].object
744
+
745
+ jsonResult.forEach(function (part, index) {
746
+ this[index] = Object.keys(this[index])
747
+ .sort((a, b) => {
748
+ if (a == 'allowCreate') return -1
749
+ if (b == 'allowCreate') return 1
750
+ if (a == 'allowRead') return -1
751
+ if (b == 'allowRead') return 1
752
+ if (a == 'allowEdit') return -1
753
+ if (b == 'allowEdit') return 1
754
+ if (a == 'allowDelete') return -1
755
+ if (b == 'allowDelete') return 1
756
+ if (a == 'viewAllRecords') return -1
757
+ if (b == 'viewAllRecords') return 1
758
+ if (a == 'modifyAllRecords') return -1
759
+ if (b == 'modifyAllRecords') return 1
760
+
761
+ return 0;
762
+ })
763
+ .reduce((accumulator, key) => {
764
+ accumulator[key] = this[index][key];
765
+
766
+ return accumulator;
767
+ }, {});
768
+ }, jsonResult);
769
+ let innerKeys = Object.keys(jsonResult[0])
770
+ innerKeys.forEach(innerKey => {
771
+ jsonResult[0][innerKey] = jsonResult[0][innerKey][0]
772
+ })
773
+
774
+ objects[key] = jsonResult
775
+ let json = {
776
+ object: undefined,
777
+ fieldPermissions: undefined
778
+ }
779
+
780
+ json.object = key
781
+ json.objectPermissions = jsonResult[0]
782
+ saveFile(json, fileName)
783
+ })
784
+ }
785
+
786
+ function pageAccesses(jsonResult, targetDir) {
787
+ let json = {
788
+ pageAccesses: undefined
789
+ }
790
+
791
+ // sort json keys to put field first
792
+ jsonResult.forEach(function (part, index) {
793
+ this[index] = Object.keys(this[index])
794
+ .sort((a, b) => {
795
+ if (a == 'apexPage') return -1
796
+ if (b == 'apexPage') return 1
797
+ if (a == 'enabled') return -1
798
+ if (b == 'enabled') return 1
799
+
800
+ return 0;
801
+ })
802
+ .reduce((accumulator, key) => {
803
+ accumulator[key] = this[index][key];
804
+
805
+ return accumulator;
806
+ }, {});
807
+ }, jsonResult);
808
+
809
+ // sort json to order by apexPage
810
+ jsonResult.sort((a, b) => {
811
+ if (a.apexPage < b.apexPage) {
812
+ return -1;
813
+ }
814
+ if (a.apexPage > b.apexPage) {
815
+ return 1;
816
+ }
817
+ return 0;
818
+ })
819
+ json.pageAccesses = jsonResult
820
+ let fileName = path.join(targetDir, 'pageAccesses' + `.${global.format}`)
821
+ saveFile(json, fileName)
822
+ }
823
+
824
+ // TODO profileActionOverrides
825
+
826
+ function recordTypeVisibilities(jsonResult, targetDir) {
827
+ const objects = {}
828
+
829
+ // populate objects with fieldPermission data per object
830
+ jsonResult.forEach(element => {
831
+ let [object] = element.recordType[0].toString().replaceAll('\n', '').trim().split('.')
832
+ if (objects[object] === undefined) {
833
+ objects[object] = []
834
+ }
835
+ objects[object].push(element)
836
+ })
837
+
838
+ // iterate objects keys (per object)
839
+ let keys = Object.keys(objects)
840
+ keys.forEach(key => {
841
+ let tag = 'recordTypeVisibilities'
842
+ let fileName = path.join(targetDir, tag, key + `.${global.format}`)
843
+
844
+ // sort json keys to put field first
845
+ let jsonResult = objects[key]
846
+ jsonResult.forEach(function (part, index) {
847
+ this[index] = Object.keys(this[index])
848
+ .sort((a, b) => {
849
+ if (a == 'recordType') return -1
850
+ if (b == 'recordType') return 1
851
+ if (a == 'default') return -1
852
+ if (b == 'default') return 1
853
+ if (a == 'visible') return -1
854
+ if (b == 'visible') return 1
855
+ if (a == 'personAccountDefault') return -1
856
+ if (b == 'personAccountDefault') return 1
857
+
858
+ return 0;
859
+ })
860
+ .reduce((accumulator, key) => {
861
+ accumulator[key] = this[index][key];
862
+
863
+ return accumulator;
864
+ }, {});
865
+ }, jsonResult);
866
+
867
+ // sort json to order by field
868
+ jsonResult.sort((a, b) => {
869
+ if (a.recordType < b.recordType) {
870
+ return -1;
871
+ }
872
+ if (a.recordType > b.recordType) {
873
+ return 1;
874
+ }
875
+ return 0;
876
+ })
877
+
878
+ let json = {
879
+ object: undefined,
880
+ recordTypeVisibilities: undefined
881
+ }
882
+
883
+ json.object = key
884
+ json.recordTypeVisibilities = jsonResult
885
+ saveFile(json, fileName)
886
+ })
887
+ }
888
+
889
+ function tabVisibilities(jsonResult, targetDir) {
890
+ let json = {
891
+ tabVisibilities: undefined
892
+ }
893
+
894
+ // sort json keys to put field first
895
+ jsonResult.forEach(function (part, index) {
896
+ this[index] = Object.keys(this[index])
897
+ .sort((a, b) => {
898
+ if (a == 'name') return -1
899
+ if (b == 'name') return 1
900
+ if (a == 'enabled') return -1
901
+ if (b == 'enabled') return 1
902
+
903
+ return 0;
904
+ })
905
+ .reduce((accumulator, key) => {
906
+ accumulator[key] = this[index][key];
907
+
908
+ return accumulator;
909
+ }, {});
910
+ }, jsonResult);
911
+
912
+ // sort json to order by name
913
+ jsonResult.sort((a, b) => {
914
+ if (a.name < b.name) {
915
+ return -1;
916
+ }
917
+ if (a.name > b.name) {
918
+ return 1;
919
+ }
920
+ return 0;
921
+ })
922
+ json.tabVisibilities = jsonResult
923
+ let fileName = path.join(targetDir, 'tabVisibilities' + `.${global.format}`)
924
+ saveFile(json, fileName)
925
+ }
926
+
927
+ function userPermissions(jsonResult, targetDir) {
928
+ let json = {
929
+ userPermissions: undefined
930
+ }
931
+
932
+ // sort json keys to put field first
933
+ jsonResult.forEach(function (part, index) {
934
+ this[index] = Object.keys(this[index])
935
+ .sort((a, b) => {
936
+ if (a == 'name') return -1
937
+ if (b == 'name') return 1
938
+ if (a == 'enabled') return -1
939
+ if (b == 'enabled') return 1
940
+
941
+ return 0;
942
+ })
943
+ .reduce((accumulator, key) => {
944
+ accumulator[key] = this[index][key];
945
+
946
+ return accumulator;
947
+ }, {});
948
+ }, jsonResult);
949
+
950
+ // sort json to order by name
951
+ jsonResult.sort((a, b) => {
952
+ if (a.name < b.name) {
953
+ return -1;
954
+ }
955
+ if (a.name > b.name) {
956
+ return 1;
957
+ }
958
+ return 0;
959
+ })
960
+ json.userPermissions = jsonResult
961
+ let fileName = path.join(targetDir, 'userPermissions' + `.${global.format}`)
962
+ saveFile(json, fileName)
963
+ }
964
+ }
965
+ }
966
+ }
967
+
968
+ function nextFrame() {
969
+ spinnerFrame = spinner.frames[index = ++index % spinner.frames.length]
970
+ return spinnerFrame
971
+ }
972
+
973
+ function saveFile(json, fileName) {
974
+ switch (global.format) {
975
+ case 'json':
976
+ let jsonString = JSON.stringify(json, null, '\t')
977
+ fs.writeFileSync(fileName, jsonString)
978
+ break
979
+ case 'yaml':
980
+ let doc = yaml.dump(json)
981
+ fs.writeFileSync(fileName, doc)
982
+ }
983
+ }