@ds-sfdc/sfparty 0.0.0 → 1.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.
@@ -1,10 +1,14 @@
1
- export const profileDefinition = {
1
+ export const metadataDefinition = {
2
2
  metaUrl: 'https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_profile.htm',
3
+ directory: 'profiles',
4
+ filetype: 'profile',
5
+ root: 'Profile',
3
6
  main: [
7
+ 'fullName',
4
8
  'custom',
5
9
  'description',
6
- 'fullName',
7
10
  'userLicense',
11
+ '$',
8
12
  ],
9
13
  singleFiles: [
10
14
  'applicationVisibilities',
@@ -29,8 +33,10 @@ export const profileDefinition = {
29
33
  'objectPermissions',
30
34
  'recordTypeVisibilities',
31
35
  ],
32
- ignore: [
33
- '$',
36
+ splitObjects: [
37
+ 'fieldPermissions',
38
+ 'objectPermissions',
39
+ 'recordTypeVisibilities',
34
40
  ],
35
41
  sortKeys: {
36
42
  'applicationVisibilities': 'application',
@@ -51,5 +57,26 @@ export const profileDefinition = {
51
57
  'recordTypeVisibilities': 'recordType',
52
58
  'tabVisibilities': 'tab',
53
59
  'userPermissions': 'name',
54
- }
60
+ },
61
+ keyOrder: {
62
+ applicationVisibilities: ['application', 'visible'],
63
+ categoryGroupVisibilities: ['dataCategoryGroup'], // TODO
64
+ classAccesses: ['apexClass', 'enabled'],
65
+ customMetadataTypeAccesses: ['name', 'enabled'],
66
+ customPermissions: ['name', 'enabled'],
67
+ customSettingAccesses: ['name', 'enabled'],
68
+ externalDataSourceAccesses: ['externalDataSource', 'enabled'],
69
+ fieldPermissions: ['field', 'editable', 'readable'],
70
+ flowAccesses: ['flow', 'enabled'],
71
+ layoutAssignments: ['layout'], // TODO
72
+ loginFlows: ['friendlyName'], // TODO
73
+ loginIpRanges: ['startAddress'], // TODO
74
+ objectPermissions: ['object', 'allowCreate', 'allowRead', 'allowEdit', 'allowDelete', 'viewAllRecords', 'modifyAllRecords'],
75
+ pageAccesses: ['apexPage', 'enabled'],
76
+ profileActionOverrides: ['pageOrSobjectType'], // TODO
77
+ recordTypeVisibilities: ['recordType', 'visible'],
78
+ tabVisibilities: ['tab', 'visibility'],
79
+ userPermissions: ['name', 'enabled'],
80
+ },
81
+ xmlFirst: 'fullName'
55
82
  }
@@ -1,5 +1,6 @@
1
1
  export const metadataDefinition = {
2
2
  metaUrl: 'https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_workflow.htm',
3
+ directory: 'workflows',
3
4
  filetype: 'workflow',
4
5
  root: 'Workflow',
5
6
  main: [
@@ -3,8 +3,9 @@ import logUpdate from 'log-update'
3
3
  import chalk from 'chalk'
4
4
  import convertHrtime from 'convert-hrtime'
5
5
  import cliSpinners from 'cli-spinners'
6
+ import os from 'node:os'
6
7
  import * as xml2js from 'xml2js'
7
- import * as fileUtils from '../fileUtils.js'
8
+ import * as fileUtils from '../lib/fileUtils.js'
8
9
 
9
10
  const spinner = cliSpinners['dots']
10
11
 
@@ -73,18 +74,18 @@ export class Combine {
73
74
  return new Promise((resolve, reject) => {
74
75
  const that = this
75
76
  if (!fileUtils.directoryExists(that.sourceDir)) reject(`Path does not exist: ${that.sourceDir}`)
77
+ let types = ['directories', 'singleFiles', 'main']
78
+ types.forEach(type => {
79
+ if (that.metadataDefinition[type] !== undefined) {
80
+ that.#types = that.#types.concat(that.metadataDefinition[type])
81
+ }
82
+ })
76
83
 
77
- if (that.metadataDefinition.directories !== undefined) {
78
- that.#types = that.#types.concat(that.metadataDefinition.directories)
79
- }
80
- if (that.metadataDefinition.singleFiles !== undefined) {
81
- that.#types = that.#types.concat(that.metadataDefinition.singleFiles)
82
- }
83
- if (that.metadataDefinition.main !== undefined) {
84
- that.#types = that.#types.concat(that.metadataDefinition.main)
85
- }
86
84
  that.#types.sort((a, b) => {
87
85
  if (a == '$') return -1
86
+ if (that.metadataDefinition.xmlFirst !== undefined) {
87
+ if (a == that.metadataDefinition.xmlFirst) return -1
88
+ }
88
89
  if (a < b) return -1
89
90
  if (a > b) return 1
90
91
  return 0
@@ -110,7 +111,7 @@ export class Combine {
110
111
  .replace('[%1]', that.sequence.toString().padStart(global.processed.total.toString().length, ' '))
111
112
  .replace('[%2]', `\n${chalk.magentaBright(nextFrame(that))} ${key}`)
112
113
  .replace('[%3]', `${that.#errorMessage}`)
113
- .replace('[%4]', `${global.statusLevel.working} `)
114
+ .replace('[%4]', `${global.icons.working} `)
114
115
  .replace('[%5]', `${that.#fileName.shortName} `)
115
116
  )
116
117
 
@@ -121,9 +122,12 @@ export class Combine {
121
122
  shortName: 'Main',
122
123
  fullName: path.join(that.sourceDir, that.metaDir, `main.${global.format}`),
123
124
  }
124
- processFile(that, key, fileObj)
125
+ processFile(that, key, fileObj, 'main')
126
+ if (that.#json.$ === undefined) {
127
+ that.#json.$ = { xmlns: 'https://soap.sforce.com/2006/04/metadata' }
128
+ }
125
129
  } else if (that.metadataDefinition.singleFiles.includes(key)) {
126
- // TODO process single file
130
+ processSingleFile(that, key)
127
131
  } else if (that.metadataDefinition.directories.includes(key)) {
128
132
  processDirectory(that, key)
129
133
  } else {
@@ -132,6 +136,15 @@ export class Combine {
132
136
  })
133
137
  }
134
138
 
139
+ function processSingleFile(that, key) {
140
+ const fileObj = {
141
+ shortName: key,
142
+ fullName: path.join(that.sourceDir, that.metaDir, key + `.${global.format}`),
143
+ }
144
+ processFile(that, key, fileObj)
145
+
146
+ }
147
+
135
148
  function processDirectory(that, key) {
136
149
  // Process the directory sourceDir/metaDir/key
137
150
  const currentDir = path.join(that.sourceDir, that.metaDir, key)
@@ -147,7 +160,7 @@ export class Combine {
147
160
  .replace('[%1]', that.sequence.toString().padStart(global.processed.total.toString().length, ' '))
148
161
  .replace('[%2]', `\n${chalk.magentaBright(nextFrame(that))} ${key} - ${index + 1} of ${fileList.length} - ${chalk.magentaBright(file)}`)
149
162
  .replace('[%3]', `${that.#errorMessage}`)
150
- .replace('[%4]', `${global.statusLevel.working} `)
163
+ .replace('[%4]', `${global.icons.working} `)
151
164
  .replace('[%5]', `${that.#fileName.shortName} `)
152
165
  )
153
166
 
@@ -162,38 +175,88 @@ export class Combine {
162
175
  return true
163
176
  }
164
177
 
165
- function processFile(that, key, fileObj = undefined) {
178
+ function processFile(that, key, fileObj = undefined, rootKey = undefined) {
166
179
  if (
167
180
  fileObj === undefined ||
168
181
  typeof fileObj != 'object' ||
169
182
  fileObj.shortName === undefined ||
170
183
  fileObj.fullName === undefined
171
184
  ) {
172
- that.#errorMessage += `\n${global.statusLevel.warn} Invalid file information passed ${chalk.redBright(fileObj)}`
185
+ that.#errorMessage += `\n${global.icons.warn} Invalid file information passed ${chalk.redBright(fileObj)}`
173
186
  return false
174
187
  }
175
188
 
176
- if (fileUtils.fileExists(fileObj.fullName)) {
177
- let result = fileUtils.readPartFile(fileObj.fullName)
178
- result = sortAndArrange(that, result, key)
179
- if (Array.isArray(that.#json[key])) {
180
- that.#json[key].push(result[key])
181
- } else {
182
- that.#json[key] = result[key][key][key]
189
+ if (!fileUtils.fileExists(fileObj.fullName)) {
190
+ return
191
+ }
192
+
193
+ let result = fileUtils.readPartFile(fileObj.fullName)
194
+
195
+ // if split by object we need to add object back to values
196
+ if (that.metadataDefinition.splitObjects !== undefined && that.metadataDefinition.splitObjects.includes(key)) {
197
+ result = hydrateObject(that, result, key, fileObj)
198
+ }
199
+ result = sortAndArrange(that, result, key)
200
+
201
+ if (Array.isArray(that.#json[key])) {
202
+ try {
203
+ if (Array.isArray(result[key])) {
204
+ result[key].forEach(arrItem => {
205
+ that.#json[key].push(arrItem)
206
+ })
207
+ } else {
208
+ that.#json[key].push(result[key])
209
+ }
210
+ } catch (error) {
211
+ throw error
212
+ }
213
+ } else {
214
+ try {
215
+ that.#json[key] = (rootKey !== undefined) ? result[rootKey][key] : result[key]
216
+ } catch (error) {
217
+ let test = { key: key, rootKey: rootKey, json: result }
218
+ throw error
183
219
  }
184
220
  }
185
221
 
186
- updateFileStats(that, fileUtils.fileInfo(fileObj.fullName).stats)
222
+ updateFileStats(that, fileObj.fullName, fileUtils.fileInfo(fileObj.fullName).stats)
187
223
  // genericXML(that, key, fileObj.fullName)
188
224
  }
189
225
 
190
- function updateFileStats(that, stats) {
191
- if (that.#fileStats.atime === undefined || stats.atime > that.#fileStats.atime) {
192
- that.#fileStats.atime = stats.atime
226
+ function hydrateObject(that, json, key, fileObj) {
227
+ const sortKey = that.metadataDefinition.sortKeys[key]
228
+ let object = json.object
229
+
230
+ try {
231
+ json[key].forEach((arrItem) => {
232
+ arrItem[sortKey] = `${object}.${arrItem[sortKey]}`.replace('.undefined', '')
233
+
234
+ // add object key if previously existed
235
+ if (that.metadataDefinition.keyOrder[key] !== undefined && that.metadataDefinition.keyOrder[key].includes('order')) {
236
+ arrItem.object = object
237
+ }
238
+ })
239
+
240
+ // delete object key that we added to the part file
241
+ delete json.object
242
+ } catch (error) {
243
+ throw error
193
244
  }
194
245
 
195
- if (that.#fileStats.mtime === undefined || stats.mtime > that.#fileStats.mtime) {
196
- that.#fileStats.mtime = stats.mtime
246
+ return json
247
+ }
248
+
249
+ function updateFileStats(that, fileName, stats) {
250
+ try {
251
+ if (that.#fileStats.atime === undefined || stats.atime > that.#fileStats.atime) {
252
+ that.#fileStats.atime = stats.atime
253
+ }
254
+
255
+ if (that.#fileStats.mtime === undefined || stats.mtime > that.#fileStats.mtime) {
256
+ that.#fileStats.mtime = stats.mtime
257
+ }
258
+ } catch (error) {
259
+ throw error
197
260
  }
198
261
  }
199
262
 
@@ -226,7 +289,7 @@ export class Combine {
226
289
  function finishMessage(that) {
227
290
  let executionTime = getTimeDiff(BigInt(that.#startTime))
228
291
  let durationMessage = `${executionTime.seconds}.${executionTime.milliseconds}s`
229
- let stateIcon = (that.#errorMessage == '') ? global.statusLevel.success : global.statusLevel.fail
292
+ let stateIcon = (that.#errorMessage == '') ? global.icons.success : global.icons.fail
230
293
 
231
294
  logUpdate(that.#spinnerMessage
232
295
  .replace('[%1]', that.sequence.toString().padStart(global.processed.total.toString().length, ' '))
@@ -250,7 +313,7 @@ export class Combine {
250
313
  }
251
314
 
252
315
  function sortJSON(json, key) {
253
- if (Array.isArray(json)) {
316
+ if (Array.isArray(json) && key !== undefined) {
254
317
  json.sort((a, b) => {
255
318
  if (a[key] < b[key]) return -1
256
319
  if (a[key] > b[key]) return 1
@@ -263,15 +326,17 @@ function sortJSON(json, key) {
263
326
  function sortAndArrange(that, json, key = undefined, topLevel = true) {
264
327
  // sort and order keys
265
328
  const sortKey = that.metadataDefinition.sortKeys[key]
266
- let jsonResult = {}
329
+
267
330
  json = arrangeKeys(that, json, key)
268
331
  json = sortJSON(json, sortKey)
269
332
 
270
333
  Object.keys(json).forEach((subKey, index, thisObj) => {
271
334
  if (typeof json[subKey] == 'object') {
272
335
  if (!Array.isArray(json[subKey])) {
273
- // call recursively on object
274
- json[subKey] = sortAndArrange(that, json[subKey], subKey)
336
+ if (Object.keys(json[subKey]).length > 1) {
337
+ // call recursively on object
338
+ json[subKey] = sortAndArrange(that, json[subKey], subKey, false)
339
+ }
275
340
  } else {
276
341
  // iterate array for objects
277
342
  json[subKey].forEach((arrItem, index) => {
@@ -284,14 +349,7 @@ function sortAndArrange(that, json, key = undefined, topLevel = true) {
284
349
  }
285
350
  })
286
351
 
287
- // we need to include the key into the json for the top-level only
288
- if (topLevel) {
289
- jsonResult[key] = json
290
- } else {
291
- jsonResult = json
292
- }
293
-
294
- return jsonResult
352
+ return json
295
353
  }
296
354
 
297
355
  function arrangeKeys(that, json, key = undefined) {
@@ -9,7 +9,7 @@ import logUpdate from 'log-update'
9
9
  import chalk from 'chalk'
10
10
  import convertHrtime from 'convert-hrtime'
11
11
  import cliSpinners from 'cli-spinners'
12
- import * as fileUtils from '../fileUtils.js'
12
+ import * as fileUtils from '../lib/fileUtils.js'
13
13
 
14
14
  const spinner = cliSpinners['dots']
15
15
 
@@ -64,55 +64,59 @@ export class Split {
64
64
  return new Promise((resolve, reject) => {
65
65
  if (!that.#fileName || !that.sourceDir || !that.targetDir || !that.metaFilePath) {
66
66
  global.logger.error('Invalid information passed to split')
67
- process.exit(1)
68
- }
69
- if (!fileUtils.fileExists(that.metaFilePath)) {
67
+ resolve(false)
68
+ } else if (!fileUtils.fileExists(that.metaFilePath)) {
70
69
  global.logger.error(`file not found: ${that.metaFilePath}`)
71
- process.exit(1)
72
- }
73
-
74
- that.targetDir = path.join(that.targetDir, that.#fileName.shortName)
75
- let parser = new Parser()
76
- const getJSON = new Promise((resolve, reject) => {
77
- readFile(that.metaFilePath, function (err, data) {
78
- parser.parseString(data, function (err, result) {
79
- if (result) {
80
- resolve(result)
81
- } else {
82
- global.logger.error(`error converting xml to json: ${that.metaFilePath}`)
83
- process.exit(1)
84
- }
70
+ resolve(false)
71
+ } else {
72
+ that.targetDir = path.join(that.targetDir, that.#fileName.shortName)
73
+ let parser = new Parser()
74
+ const getJSON = new Promise((resolve, reject) => {
75
+ readFile(that.metaFilePath, function (err, data) {
76
+ parser.parseString(data, function (err, result) {
77
+ if (result) {
78
+ resolve({ data: result, startTime: process.hrtime.bigint() })
79
+ } else {
80
+ global.logger.error(`error converting xml to json: ${that.metaFilePath}`)
81
+ reject(`error converting xml to json: ${that.metaFilePath}`)
82
+ }
83
+ })
85
84
  })
86
85
  })
87
- })
88
- getJSON.then((result) => {
89
- try {
90
- result[that.#root]['$'].xmlns = result[that.#root]['$'].xmlns.replace('http:', 'https:')
91
- } catch (error) {
92
- global.logger.error(`${that.#fileName.fullName} has an invalid XML root`)
93
- resolve(false)
94
- return
95
- }
86
+ getJSON.catch((error) => {
87
+ throw error
88
+ })
89
+ getJSON.then((result) => {
90
+ that.#startTime = result.startTime
91
+ result = result.data
92
+ try {
93
+ result[that.#root]['$'].xmlns = result[that.#root]['$'].xmlns.replace('http:', 'https:')
94
+ } catch (error) {
95
+ global.logger.error(`${that.#fileName.fullName} has an invalid XML root`)
96
+ resolve(false)
97
+ return
98
+ }
96
99
 
97
- // modify the json to remove unwanted arrays
98
- that.#json = transformJSON(that, result, that.#root)
99
- fileUtils.deleteDirectory(that.targetDir, true) // recursive delete existing directory
100
- fileUtils.createDirectory(that.targetDir) // create directory
101
-
102
- try {
103
- processJSON(that, that.#json[that.#root], that.targetDir)
104
- completeFile(that)
105
- } catch (error) {
106
- console.log(that.#fileName.shortName)
107
- global.logger.error(error)
108
- }
100
+ // modify the json to remove unwanted arrays
101
+ that.#json = transformJSON(that, result, that.#root)
102
+ fileUtils.deleteDirectory(that.targetDir, true) // recursive delete existing directory
103
+ fileUtils.createDirectory(that.targetDir) // create directory
104
+
105
+ try {
106
+ processJSON(that, that.#json[that.#root], that.targetDir)
107
+ completeFile(that)
108
+ } catch (error) {
109
+ console.log(that.#fileName.shortName)
110
+ global.logger.error(error)
111
+ throw error
112
+ }
109
113
 
110
- resolve(true)
111
- })
114
+ resolve(true)
115
+ })
116
+ }
112
117
  })
113
118
 
114
119
  function processJSON(that, json, baseDir) {
115
- that.#startTime = process.hrtime.bigint()
116
120
  that.#spinnerMessage = `[%1] of ${global.processed.total} - Workflow: [%4]${chalk.yellowBright(that.#fileName.shortName)}[%2][%3]`
117
121
 
118
122
  let targetDir = baseDir
@@ -122,42 +126,47 @@ export class Split {
122
126
  .replace('[%1]', that.sequence.toString().padStart(global.processed.total.toString().length, ' '))
123
127
  .replace('[%2]', `\n${chalk.magentaBright(nextFrame(that))} ${key}`)
124
128
  .replace('[%3]', `${that.#errorMessage}`)
125
- .replace('[%4]', `${global.statusLevel.working} `)
129
+ .replace('[%4]', `${global.icons.working} `)
126
130
  )
127
131
 
128
- if (that.metadataDefinition.directories.includes(key)) {
132
+ if (that.metadataDefinition.directories !== undefined && that.metadataDefinition.directories.includes(key)) {
129
133
  targetDir = path.join(baseDir, key)
130
134
  fileUtils.createDirectory(targetDir) // create directory
131
135
  if (Array.isArray(json[key])) {
132
136
  processDirectory(that, json[key], key, targetDir)
133
137
  }
134
- } else if (that.metadataDefinition.singleFiles.includes(key)) {
135
- console.log(key, 'single file')
136
- } else if (that.metadataDefinition.main.includes(key)) {
138
+ } else if (that.metadataDefinition.singleFiles !== undefined && that.metadataDefinition.singleFiles.includes(key)) {
139
+ processFile(that, json[key], key, baseDir)
140
+ } else if (that.metadataDefinition.main !== undefined && that.metadataDefinition.main.includes(key)) {
137
141
  // Main will get processed in it's own call
138
142
  } else {
139
- console.log(key, 'unknown')
143
+ logUpdate(key, 'unknown')
144
+ logUpdate.done()
140
145
  }
141
146
  })
142
147
 
143
- Main(that)
148
+ if (that.metadataDefinition.main !== undefined) {
149
+ Main(that)
150
+ }
144
151
  }
145
152
 
146
153
  function Main(that) {
147
154
  let fileName = path.join(that.targetDir, `main.${global.format}`)
148
- let mainInfo = {}
149
- mainInfo.name = that.#fileName.shortName
155
+ let mainInfo = {
156
+ main: {}
157
+ }
158
+ mainInfo.main.name = that.#fileName.shortName
150
159
  that.metadataDefinition.main.forEach(key => {
151
160
  that.sequence = global.processed.current
152
161
  logUpdate(that.#spinnerMessage
153
162
  .replace('[%1]', that.sequence.toString().padStart(global.processed.total.toString().length, ' '))
154
163
  .replace('[%2]', `\n${chalk.magentaBright(nextFrame(that))} ${key}`)
155
164
  .replace('[%3]', `${that.#errorMessage}`)
156
- .replace('[%4]', `${global.statusLevel.working} `)
165
+ .replace('[%4]', `${global.icons.working} `)
157
166
  )
158
167
 
159
168
  if (that.#json[that.#root][key] !== undefined) {
160
- mainInfo[key] = that.#json[that.#root][key]
169
+ mainInfo.main[key] = that.#json[that.#root][key]
161
170
  }
162
171
  })
163
172
 
@@ -171,7 +180,7 @@ export class Split {
171
180
  function completeFile(that) {
172
181
  let executionTime = getTimeDiff(BigInt(that.#startTime))
173
182
  let durationMessage = `${executionTime.seconds}.${executionTime.milliseconds}s`
174
- let stateIcon = (that.#errorMessage == '') ? global.statusLevel.success : global.statusLevel.fail
183
+ let stateIcon = (that.#errorMessage == '') ? global.icons.success : global.icons.fail
175
184
  logUpdate(that.#spinnerMessage
176
185
  .replace('[%1]', that.sequence.toString().padStart(global.processed.total.toString().length, ' '))
177
186
  .replace('[%2]', `. Processed in ${durationMessage}.`)
@@ -184,11 +193,52 @@ export class Split {
184
193
  }
185
194
 
186
195
  function processDirectory(that, json, key, baseDir) {
187
- json.forEach(arrItem => {
196
+ if (that.metadataDefinition.splitObjects !== undefined && that.metadataDefinition.splitObjects.includes(key)) {
188
197
  const sortKey = that.metadataDefinition.sortKeys[key]
189
- let fileName = path.join(baseDir, `${arrItem[sortKey]}.${global.format}`)
190
- fileUtils.savePartFile(arrItem, fileName, global.format)
191
- })
198
+ const objects = {}
199
+
200
+ if (sortKey === undefined) {
201
+ throw new Error(`No sort key specified for: ${key}`)
202
+ }
203
+ json.forEach(arrItem => {
204
+ const object = arrItem[sortKey].split('.')[0]
205
+ arrItem[sortKey] = arrItem[sortKey].split('.').pop()
206
+ if (objects[object] === undefined) {
207
+ objects[object] = {
208
+ object: object
209
+ }
210
+ objects[object][key] = []
211
+ }
212
+ delete arrItem['object']
213
+ objects[object][key].push(arrItem)
214
+ })
215
+
216
+ Object.keys(objects).forEach(object => {
217
+ processFile(that, objects[object], key, baseDir, object)
218
+ })
219
+
220
+ } else {
221
+ json.forEach(arrItem => {
222
+ processFile(that, arrItem, key, baseDir)
223
+ })
224
+ }
225
+
226
+
227
+ }
228
+
229
+ function processFile(that, json, key, baseDir, fileNameOverride) {
230
+ let newJSON
231
+ let fileName
232
+ if (fileNameOverride !== undefined) {
233
+ fileName = path.join(baseDir, `${fileNameOverride}.${global.format}`)
234
+ newJSON = json
235
+ } else {
236
+ const sortKey = that.metadataDefinition.sortKeys[key]
237
+ fileName = path.join(baseDir, `${(json[sortKey] !== undefined) ? json[sortKey] : key}.${global.format}`)
238
+ newJSON = {}
239
+ newJSON[key] = json
240
+ }
241
+ fileUtils.savePartFile(newJSON, fileName, global.format)
192
242
  }
193
243
 
194
244
  function transformJSON(that, result, rootTag) {
@@ -230,17 +280,22 @@ function keySort(that, key, json) {
230
280
 
231
281
  // arrange json keys in specified order using keyOrder
232
282
  json.forEach(function (part, index) {
233
- this[index] = Object.keys(this[index])
234
- .sort((a, b) => {
235
- if (keyOrder.indexOf(a) == -1) return 1
236
- if (keyOrder.indexOf(a) < keyOrder.indexOf(b)) return -1
237
- if (keyOrder.indexOf(a) > keyOrder.indexOf(b)) return 1
238
- return 0
239
- })
240
- .reduce((accumulator, key) => {
241
- accumulator[key] = this[index][key]
242
- return accumulator
243
- }, {})
283
+ try {
284
+ this[index] = Object.keys(this[index])
285
+ .sort((a, b) => {
286
+ if (keyOrder.indexOf(a) == -1) return 1
287
+ if (keyOrder.indexOf(a) < keyOrder.indexOf(b)) return -1
288
+ if (keyOrder.indexOf(a) > keyOrder.indexOf(b)) return 1
289
+ return 0
290
+ })
291
+ .reduce((accumulator, key) => {
292
+ accumulator[key] = this[index][key]
293
+ return accumulator
294
+ }, {})
295
+ } catch (error) {
296
+ let test = key
297
+ throw error
298
+ }
244
299
  }, json)
245
300
 
246
301
  // recursive objects