Passed
Push — master ( ae58d1...b549a3 )
by Barry
01:11
created

src/jsonSnip.js   B

Complexity

Total Complexity 37
Complexity/F 4.11

Size

Lines of Code 159
Function Count 9

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 0
c 1
b 0
f 0
nc 1
dl 0
loc 159
rs 8.6
wmc 37
mnd 5
bc 38
fnc 9
bpm 4.2222
cpm 4.1111
noi 0

8 Functions

Rating   Name   Duplication   Size   Complexity  
A jsonSnip.js ➔ deleteJsonKey 0 14 3
A jsonSnip.js ➔ jsonDelKeys 0 11 3
B jsonSnip.js ➔ jsonEllipsify 0 21 6
A jsonSnip.js ➔ json 0 5 1
B jsonSnip.js ➔ minimizeJsonProperty 0 34 6
A jsonSnip.js ➔ buildJsonSearchPath 0 7 2
C jsonSnip.js ➔ jsonSnippet 0 33 7
B jsonSnip.js ➔ jsonPrettify 0 19 6
1
const jp = require('jsonpath')
2
const {setInputType, removeQuotes} = require('./commonFuncs.js')
3
4
function buildJsonSearchPath (keyName) {
5
  if (keyName.substr(0, 1) === '$') {
6
    return keyName
7
  } else {
8
    return "$..['" + keyName + "']"
9
  }
10
}
11
12
// =================json===============================
13
export function json (inpObj) {
14
    // cmdArgs is an array of arguments
15
    // json is an object containing the json object we need to modify
16
  setInputType(inpObj, 'json') // all we do is flag our content as being json
17
}
18
19
// =================jsonPrettify=======================
20
export function jsonPrettify (inpObj, cmdArgs) {
21
  // cmdArgs is an (optional) array of arguments being indent, maxLength, margins
22
  // they are all passed as strings so need to be converted to numbers where appropriate
23
  // we use - 0 to convert string numbers to numeric and === against itself to check for NaN
24
  if (setInputType(inpObj, 'json')) {
25
    let opts = inpObj.outputOptions
26
    // set defaults
27
    opts.margins = false
28
    opts.maxLength = 45
29
    opts.indent = 2
30
    // overwrite with any values passed in
31
    if (cmdArgs !== undefined) {
32
      if ((cmdArgs[0] - 0) === (cmdArgs[0] - 0)) { opts.indent = (cmdArgs[0] - 0) }
33
      if ((cmdArgs[1] - 0) === (cmdArgs[1] - 0)) { opts.maxLength = (cmdArgs[1] - 0) }
34
      if (cmdArgs[1] === 'infinity') { opts.maxLength = 'infinity' }
35
      opts.margins = (cmdArgs[2] === 'true') // defaults to false if margins anything other than true
36
    }
37
  }
38
}
39
40
// =================ellipsify==========================
41
export function jsonEllipsify (inpObj, cmdArgs) {
42
  // cmdArgs is an array of arguments
43
  // json is an object containing the json object we need to modify
44
45
  if (setInputType(inpObj, 'json')) {
46
    // we have two types of argument for Ellipsify, plain and exclude so separate them out
47
    var cmdArgsPlain = []
48
    var cmdArgsExclude = []
49
    for (let i = 0; i < cmdArgs.length; i++) {
50
      if (cmdArgs[i].substr(0, 1) === '~') {
51
        cmdArgsExclude.push(removeQuotes(cmdArgs[i].substr(1)))
52
      } else {
53
        cmdArgsPlain.push(removeQuotes(cmdArgs[i]))
54
      }
55
    }
56
    if (cmdArgsPlain.length === 0) { cmdArgsPlain.push('$') }
57
    for (let i = 0; i < cmdArgsPlain.length; i++) {
58
      minimizeJsonProperty(inpObj.json, cmdArgsPlain[i], cmdArgsExclude)
59
    }
60
  }
61
}
62
63
export function minimizeJsonProperty (json, property, excludes) { // only exported for test purposes
64
  // this function takes a json object as input.and for every occurrence of the given property puts a placeholder
65
  // but only if it is an array or an object.
66
  var arrPlaceholder = ['fsnipPlaceholderArrEllipses'] // a valid json array used as a placeholder to be replaced later with [...] (which is not valid json)
67
  var strPlaceholder = 'fsnipPlaceholderStrEllipses'
68
  var jsonPaths = jp.paths(json, buildJsonSearchPath(property)) // creates an array of all the paths of instances of the the property we want to minimize
69
  for (var i = 0; i < jsonPaths.length; i++) {
70
    let jsonPath = jp.stringify(jsonPaths[i])
71
    switch (jp.value(json, jsonPath).constructor.name) {
72
      case 'Object':
73
        delKeys(json, jsonPath, excludes)
74
        jp.value(json, jsonPath)['fsnipPlaceholderObj'] = 'Ellipses' // add a placeholder for the Ellipses
75
        break
76
      case 'Array':
77
        jp.value(json, jsonPath, arrPlaceholder)
78
        break
79
      case 'String':
80
        jp.value(json, jsonPath, strPlaceholder)
81
        break
82
      default:
83
        // do nothing
84
    }
85
  }
86
87
  function delKeys (json, jsonPath, excludes) {
88
    var keys = Object.keys(jp.value(json, jsonPath))
89
    for (var j = 0; j < keys.length; j++) {
90
      if (excludes.indexOf(keys[j]) === -1) {
91
        // this key is not in the excludes list so we need to delete it
92
        delete jp.value(json, jsonPath)[keys[j]]
93
      }
94
    }
95
  }
96
}
97
98
// ===================snip Function==============================
99
export function jsonSnippet (inpObj, cmdArgs) {
100
  // cmdArgs is an array of arguments
101
  // inpObj is an object containing the json object we need to modify
102
  // the format of the call is eg.
103
  // '--snip vessel 2' which would extract the second instance of "vessel" in the json supplied
104
  // with the instance identifier being optional
105
  if (setInputType(inpObj, 'json')) {
106
    var occ = 1
107
    if (cmdArgs.length === 1) {
108
      occ = 1 // by default we snip the first occurrence of this property
109
    } else if (cmdArgs.length === 2) {
110
      if ((cmdArgs[1] - 0) === (cmdArgs[1] - 0)) {
111
        occ = (cmdArgs[1] - 0)
112
        if (occ < 1) {
113
          inpObj.error.push('--snip requires its second argument to be a numeric values of at least 1 being the instance required')
114
          return
115
        }
116
      } else {
117
        inpObj.error.push("--snip requires its second argument to be numeric eg. '--snip vessel 2' with the optional second argument being the instance required")
118
        return
119
      }
120
    } else {
121
      inpObj.error.push("--snip requires 1 or 2 arguments eg. '--snip vessel 2' with the optional second argument being the instance required.")
122
      return
123
    }
124
    var jsonPaths = jp.paths(inpObj.json, buildJsonSearchPath(removeQuotes(cmdArgs[0]))) // creates an array of all the paths to this property
125
    if (jsonPaths.length < occ) {
126
      inpObj.error.push('--snip failed because there were only ' + jsonPaths.length + " occurrences of '" + removeQuotes(cmdArgs[0]) + "' found.")
127
      return
128
    }
129
    inpObj.json = jp.value(inpObj.json, jp.stringify(jsonPaths[occ - 1]))
130
  }
131
}
132
133
// ===================delKeys Function===========================
134
export function jsonDelKeys (inpObj, cmdArgs) {
135
  // cmdArgs is an array of arguments
136
  // inpObj is an object containing the json object we need to remove keys from
137
  // the format of the call is eg.
138
  // '-jsonDelKeys vessel gnss' which would delete all instances of "vessel" and "gnss" in the json supplied
139
  if (setInputType(inpObj, 'json')) {
140
    for (var i = 0; i < cmdArgs.length; i++) {
141
      deleteJsonKey(inpObj.json, removeQuotes(cmdArgs[i]))
142
    }
143
  }
144
}
145
146
function deleteJsonKey (json, key) {
147
  // deletes all occurrences of key within json
148
  var jsonPaths = jp.paths(json, buildJsonSearchPath(key)) // creates an array of all the paths of instances of the key we want to delete
149
  var parent
150
  for (var i = 0; i < jsonPaths.length; i++) {
151
    let jsonPath = jp.stringify(jsonPaths[i])
152
    parent = jp.parent(json, jsonPath)
153
    if (Array.isArray(parent)) {
154
      parent.splice(jsonPaths[i][jsonPaths[i].length - 1], 1)
155
    } else {
156
      delete parent[jsonPaths[i][jsonPaths[i].length - 1]]
157
    }
158
  }
159
}
160