@ds-sfdc/sfparty 0.0.0 → 1.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.
- package/.husky/commit-msg +4 -0
- package/commitlint.config.cjs +1 -0
- package/package.json +10 -7
- package/{index.js → src/index.js} +125 -186
- package/{lib → src/lib}/fileUtils.js +18 -10
- package/{lib → src/lib}/permset/combine.js +5 -5
- package/{lib → src/lib}/permset/split.js +4 -4
- package/{lib → src/lib}/profile/combine.js +5 -5
- package/{lib → src/lib}/profile/split.js +1 -1
- package/{lib/label/definition.js → src/meta/CustomLabels.js} +12 -1
- package/{lib/permset/definition.js → src/meta/PermissionSets.js} +10 -17
- package/{lib/profile/definition.js → src/meta/Profiles.js} +32 -5
- package/{lib/workflow/definition.js → src/meta/Workflows.js} +1 -0
- package/{lib/workflow → src/party}/combine.js +100 -42
- package/{lib/workflow → src/party}/split.js +124 -69
- package/lib/label/combine.js +0 -203
- package/lib/label/split.js +0 -213
|
@@ -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
|
-
|
|
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
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
143
|
+
logUpdate(key, 'unknown')
|
|
144
|
+
logUpdate.done()
|
|
140
145
|
}
|
|
141
146
|
})
|
|
142
147
|
|
|
143
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
196
|
+
if (that.metadataDefinition.splitObjects !== undefined && that.metadataDefinition.splitObjects.includes(key)) {
|
|
188
197
|
const sortKey = that.metadataDefinition.sortKeys[key]
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
|
|
234
|
-
.
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
accumulator
|
|
242
|
-
|
|
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
|
package/lib/label/combine.js
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
import os from 'os'
|
|
3
|
-
import { readFileSync, writeFileSync, utimesSync } from 'fs'
|
|
4
|
-
import logUpdate from 'log-update'
|
|
5
|
-
import chalk from 'chalk'
|
|
6
|
-
import convertHrtime from 'convert-hrtime'
|
|
7
|
-
import cliSpinners from 'cli-spinners'
|
|
8
|
-
import * as fileUtils from '../fileUtils.js'
|
|
9
|
-
import { labelDefinition } from './definition.js'
|
|
10
|
-
import * as xml2js from 'xml2js'
|
|
11
|
-
import * as yaml from 'js-yaml'
|
|
12
|
-
|
|
13
|
-
const spinner = cliSpinners['dots']
|
|
14
|
-
|
|
15
|
-
export class CustomLabel {
|
|
16
|
-
#xml = ''
|
|
17
|
-
#types = []
|
|
18
|
-
#spinnerMessage = ''
|
|
19
|
-
#index = 0
|
|
20
|
-
#startTime = 0
|
|
21
|
-
#fileName = ''
|
|
22
|
-
#errorMessage = ''
|
|
23
|
-
#fileStats
|
|
24
|
-
|
|
25
|
-
constructor(config) {
|
|
26
|
-
this.sourceDir = config.sourceDir
|
|
27
|
-
this.targetDir = config.targetDir
|
|
28
|
-
this.metaDir = config.metaDir
|
|
29
|
-
this.processList = config.processList
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
combine() {
|
|
33
|
-
return new Promise((resolve, reject) => {
|
|
34
|
-
const that = this
|
|
35
|
-
if (!fileUtils.directoryExists(that.sourceDir)) reject(`Path does not exist: ${that.sourceDir}`)
|
|
36
|
-
|
|
37
|
-
that.#xml = `<?xml version="1.0" encoding="UTF-8"?>${os.EOL}`
|
|
38
|
-
that.#xml += `<CustomLabels xmlns="https://soap.sforce.com/2006/04/metadata">${os.EOL}`
|
|
39
|
-
|
|
40
|
-
labelDefinition.directories.forEach(key => { that.#types.push(key) })
|
|
41
|
-
that.#types.sort()
|
|
42
|
-
|
|
43
|
-
setFileName(that)
|
|
44
|
-
processLabel(that)
|
|
45
|
-
|
|
46
|
-
saveXML(that)
|
|
47
|
-
resolve(true)
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
function setFileName(that) {
|
|
51
|
-
that.#fileName = path.join(that.targetDir, 'CustomLabels.labels-meta.xml')
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function processLabel(that) {
|
|
55
|
-
that.#startTime = process.hrtime.bigint()
|
|
56
|
-
that.#spinnerMessage = `[%1] of ${global.processed.total} - Custom Label: [%4]${chalk.yellowBright('[%5]')}[%2][%3]`
|
|
57
|
-
that.processList.sort()
|
|
58
|
-
that.#types.forEach(key => {
|
|
59
|
-
processDirectory(that, key)
|
|
60
|
-
})
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function processFile(that, key) {
|
|
64
|
-
const fileName = path.join(that.sourceDir, that.metaDir, `${key}.${global.format}`)
|
|
65
|
-
if (fileUtils.fileExists(fileName)) {
|
|
66
|
-
if (labelDefinition.singleFiles.includes(key)) {
|
|
67
|
-
genericXML(that, key)
|
|
68
|
-
} else {
|
|
69
|
-
that.#errorMessage += `\n${global.statusLevel.warn} Not processed: ${key}`
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function processDirectory(that, key) {
|
|
75
|
-
that.sequence = 0
|
|
76
|
-
let startTime
|
|
77
|
-
that.#errorMessage = ''
|
|
78
|
-
that.processList.forEach(fileName => {
|
|
79
|
-
startTime = process.hrtime.bigint()
|
|
80
|
-
that.sequence++
|
|
81
|
-
logUpdate(that.#spinnerMessage
|
|
82
|
-
.replace('[%1]', that.sequence.toString().padStart(global.processed.total.toString().length, ' '))
|
|
83
|
-
.replace('[%2]', `\n${chalk.magentaBright(nextFrame(that))} ${key}`)
|
|
84
|
-
.replace('[%3]', `${that.#errorMessage}`)
|
|
85
|
-
.replace('[%4]', `${global.statusLevel.working} `)
|
|
86
|
-
.replace('[%5]', `${fileName} `)
|
|
87
|
-
)
|
|
88
|
-
try {
|
|
89
|
-
genericXML(that, key, fileName)
|
|
90
|
-
} catch (error) {
|
|
91
|
-
that.#errorMessage = error.message
|
|
92
|
-
}
|
|
93
|
-
let executionTime = getTimeDiff(BigInt(startTime))
|
|
94
|
-
let durationMessage = `${executionTime.seconds}.${executionTime.milliseconds}s`
|
|
95
|
-
let stateIcon = (that.#errorMessage == '') ? global.statusLevel.success : global.statusLevel.fail
|
|
96
|
-
logUpdate(that.#spinnerMessage
|
|
97
|
-
.replace('[%1]', that.sequence.toString().padStart(global.processed.total.toString().length, ' '))
|
|
98
|
-
.replace('[%2]', `. Processed in ${durationMessage}.`)
|
|
99
|
-
.replace('[%3]', `${that.#errorMessage}`)
|
|
100
|
-
.replace('[%4]', `${stateIcon} `)
|
|
101
|
-
.replace('[%5', fileName)
|
|
102
|
-
)
|
|
103
|
-
logUpdate.done()
|
|
104
|
-
})
|
|
105
|
-
// TODO that.#fileStats = fileUtils.fileInfo(fileName).stats
|
|
106
|
-
|
|
107
|
-
// genericDirectoryXML(that, key)
|
|
108
|
-
// that.#errorMessage += `\n${global.statusLevel.warn} Not processed: ${key}`
|
|
109
|
-
return true
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function getTimeDiff(startTime, endTime = process.hrtime.bigint()) {
|
|
113
|
-
const diff = BigInt(endTime) - BigInt(startTime)
|
|
114
|
-
let executionTime = convertHrtime(diff)
|
|
115
|
-
executionTime.seconds = Math.round(executionTime.seconds)
|
|
116
|
-
executionTime.milliseconds = Math.round(executionTime.milliseconds / 1000)
|
|
117
|
-
if (executionTime.milliseconds == 0 && executionTime.nanoseconds > 0) executionTime.milliseconds = 1
|
|
118
|
-
return executionTime
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function saveXML(that) {
|
|
122
|
-
fileUtils.createDirectory(that.targetDir)
|
|
123
|
-
that.#xml += '</CustomLabels>\n'
|
|
124
|
-
writeFileSync(that.#fileName, that.#xml)
|
|
125
|
-
// utimesSync(that.#fileName, that.#fileStats.atime, that.#fileStats.mtime)
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function nextFrame(that) {
|
|
130
|
-
return spinner.frames[that.#index = ++that.#index % spinner.frames.length]
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function genericXML(that, key, fileName) {
|
|
134
|
-
fileName = path.join(that.sourceDir, fileName)
|
|
135
|
-
const builder = new xml2js.Builder({ cdata: false, headless: true, rootName: key })
|
|
136
|
-
if (fileUtils.fileExists(fileName)) {
|
|
137
|
-
const data = readFileSync(fileName, { encoding: 'utf8', flag: 'r' })
|
|
138
|
-
const result = (global.format == 'yaml') ? yaml.load(data) : JSON.parse(data)
|
|
139
|
-
result[key.slice(0, -1)][labelDefinition.sortKeys[key]] = result[labelDefinition.sortKeys[key]]
|
|
140
|
-
result[key.slice(0, -1)] = sortJSONKeys(sortJSON(result[key.slice(0, -1)], labelDefinition.sortKeys[key]))
|
|
141
|
-
that.#xml += `\t<${key}>${os.EOL}`
|
|
142
|
-
Object.keys(result[key.slice(0, -1)]).forEach(tag => {
|
|
143
|
-
let xml
|
|
144
|
-
try {
|
|
145
|
-
xml = builder.buildObject(result[key.slice(0, -1)][tag]).replace(`<${key}>`, '').replace(`</${key}>`, '')
|
|
146
|
-
that.#xml += `\t\t<${tag}>${xml}</${tag}>${os.EOL}`
|
|
147
|
-
} catch (error) {
|
|
148
|
-
global.logger.error(error)
|
|
149
|
-
}
|
|
150
|
-
})
|
|
151
|
-
that.#xml += `\t</${key}>${os.EOL}`
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
// end of functions
|
|
155
|
-
// end of combine
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// end of class
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function sortJSON(json, key) {
|
|
162
|
-
if (Array.isArray(json)) {
|
|
163
|
-
json.sort((a, b) => {
|
|
164
|
-
if (a[key] < b[key]) return -1
|
|
165
|
-
if (a[key] > b[key]) return 1
|
|
166
|
-
return 0
|
|
167
|
-
})
|
|
168
|
-
}
|
|
169
|
-
return json
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function sortJSONKeys(json) {
|
|
173
|
-
// sort json keys alphabetically
|
|
174
|
-
if (Array.isArray(json)) {
|
|
175
|
-
json.forEach(function (part, index) {
|
|
176
|
-
this[index] = Object.keys(this[index])
|
|
177
|
-
.sort((a, b) => {
|
|
178
|
-
if (a < b) return -1
|
|
179
|
-
if (a > b) return 1
|
|
180
|
-
return 0
|
|
181
|
-
})
|
|
182
|
-
.reduce((accumulator, key) => {
|
|
183
|
-
accumulator[key] = this[index][key]
|
|
184
|
-
|
|
185
|
-
return accumulator
|
|
186
|
-
}, {})
|
|
187
|
-
}, json)
|
|
188
|
-
|
|
189
|
-
} else {
|
|
190
|
-
json = Object.keys(json)
|
|
191
|
-
.sort((a, b) => {
|
|
192
|
-
if (a < b) return -1
|
|
193
|
-
if (a > b) return 1
|
|
194
|
-
return 0
|
|
195
|
-
})
|
|
196
|
-
.reduce((accumulator, key) => {
|
|
197
|
-
accumulator[key] = json[key]
|
|
198
|
-
|
|
199
|
-
return accumulator
|
|
200
|
-
}, {})
|
|
201
|
-
}
|
|
202
|
-
return json
|
|
203
|
-
}
|