Completed
Push — master ( 39b560...f48291 )
by greg
01:42
created

src/cli/cms/data/file.js   D

Complexity

Total Complexity 64
Complexity/F 5.82

Size

Lines of Code 267
Function Count 11

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 0
wmc 64
c 1
b 0
f 0
nc 1
mnd 5
bc 37
fnc 11
dl 0
loc 267
rs 4.5964
bpm 3.3636
cpm 5.8181
noi 6

7 Functions

Rating   Name   Duplication   Size   Complexity  
A file.js ➔ fromUrl 0 56 3
A file.js ➔ getFiles 0 16 1
A file.js ➔ get 0 15 3
A file.js ➔ getFolders 0 13 1
A file.js ➔ getFilesByType 0 19 3
B file.js ➔ getAllWithKeys 0 44 1
F file.js ➔ read 0 87 20

How to fix   Complexity   

Complexity

Complex classes like src/cli/cms/data/file.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import path from 'path'
2
import fse from 'fs-extra'
3
import moment from 'moment'
4
5
import {
6
  Hooks,
7
  coreUtils,
8
  cmsData,
9
  config
10
} from '../../'
11
12
export function getAllWithKeys(withKeys) {
13
  var files = cmsData.file.getFiles(path.join(config.root, config.data.url), true, 99, /\.json/)
14
  var filesArr = []
15
16
  files.forEach(function (file) {
17
    var cleanFile = file
18
    var json = cmsData.file.get(file.path)
19
20
    if(typeof json.abe_meta.latest !== 'undefined' && json.abe_meta.latest !== null
21
      && typeof json.abe_meta.latest !== 'undefined' && json.abe_meta.latest !== null
22
      && typeof json.abe_meta.latest.date !== 'undefined' && json.abe_meta.latest.date !== null) {
23
      file.date = json.abe_meta.latest.date
24
    }
25
26
    if(typeof json.abe_meta !== 'undefined' && json.abe_meta !== null) {
27
      var date = null
28
      if (typeof json.abe_meta.latest !== 'undefined' && json.abe_meta.latest !== null
29
        && typeof json.abe_meta.latest.date !== 'undefined' && json.abe_meta.latest.date !== null) {
30
        date = json.abe_meta.latest.date
31
      }else if (typeof json.abe_meta.date !== 'undefined' && json.abe_meta.date !== null) {
32
        date = json.abe_meta.date
33
      }
34
      cleanFile.abe_meta = {
35
        date: date
36
        , type: (typeof json.abe_meta.type !== 'undefined' && json.abe_meta.type !== null) ? json.abe_meta.type : null
37
        , link: (typeof json.abe_meta.link !== 'undefined' && json.abe_meta.link !== null) ? json.abe_meta.link : null
38
        , template: (typeof json.abe_meta.template !== 'undefined' && json.abe_meta.template !== null) ? json.abe_meta.template : null
39
        , status: (typeof json.abe_meta.status !== 'undefined' && json.abe_meta.status !== null) ? json.abe_meta.status : null
40
        , cleanName: (typeof json.abe_meta.cleanName !== 'undefined' && json.abe_meta.cleanName !== null) ? json.abe_meta.cleanName : null
41
        , cleanFilename: (typeof json.abe_meta.cleanFilename !== 'undefined' && json.abe_meta.cleanFilename !== null) ? json.abe_meta.cleanFilename : null
42
      }
43
    }
44
    Array.prototype.forEach.call(withKeys, (key) => {
45
      var keyFirst = key.split('.')[0]
46
      cleanFile[keyFirst] = json[keyFirst]
47
    })
48
    filesArr.push(cleanFile)
49
  })
50
51
  var merged = cmsData.revision.getFilesMerged(filesArr)
52
53
  Hooks.instance.trigger('afterGetAllFiles', merged)
54
  return merged
55
}
56
57
export function get(pathJson) {
58
  var json = {}
59
  pathJson = Hooks.instance.trigger('beforeGetJson', pathJson)
60
  
61
  try {
62
    var stat = fse.statSync(pathJson)
63
    if (stat) {
64
      json = fse.readJsonSync(pathJson)
65
    }
66
  }catch(e) {
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
67
  }
68
69
  json = Hooks.instance.trigger('afterGetJson', json)
70
  return json
71
}
72
73
export function fromUrl(url) {
74
  var res = {
75
    root: '',
76
    draft: {
77
      dir: '',
78
      file: '',
79
      path: ''
80
    },
81
    publish: {
82
      dir: '',
83
      file: '',
84
      link: '',
85
      path: '',
86
      json: ''
87
    },
88
    json: {
89
      path: '',
90
      file: ''
91
    }
92
  }
93
94
  if(typeof url !== 'undefined' && url !== null) {
95
96
    var dir = path.dirname(url).replace(config.root, '')
97
    var filename = path.basename(url)
98
    var link = url.replace(config.root, '')
99
    link = link.replace(/^\//, '').split('/')
100
    link.shift()
101
    link = cmsData.fileAttr.delete('/' + link.join('/').replace(/\/$/, ''))
102
103
    let draft = config.draft.url
104
    let publish = config.publish.url
105
    let data = config.data.url
106
107
    res.root = config.root
108
109
    // set dir path draft/json
110
    res.draft.dir = coreUtils.file.changePath(dir, draft)
111
    res.json.dir = coreUtils.file.changePath(dir, data)
112
    res.publish.dir = coreUtils.file.changePath(dir, publish)
113
    res.publish.json = res.json.dir
114
115
    // set filename draft/json
116
    res.draft.file = filename
117
    res.publish.file = cmsData.fileAttr.delete(filename)
118
    res.publish.link = link
119
    res.json.file = filename.replace(`.${config.files.templates.extension}`, '.json')
120
    res.publish.json = path.join(res.json.dir, cmsData.fileAttr.delete(res.json.file))
121
122
    // set filename draft/json
123
    res.draft.path = path.join(res.draft.dir, res.draft.file)
124
    res.publish.path = path.join(res.publish.dir, res.publish.file)
125
    res.json.path = path.join(res.json.dir, res.json.file)
126
  }
127
  return res
128
}
129
130
export function getFolders(folder, flatten = false, level) {
131
  var arr = []
0 ignored issues
show
Unused Code introduced by
The assignment to variable arr seems to be never used. Consider removing it.
Loading history...
132
  arr = cmsData.file.read(
133
    folder.replace(/\/$/, ''), 
134
    folder.replace(/\/$/, ''), 
135
    'folders', 
136
    flatten, 
137
    /(.*?)/, 
138
    level
139
  )
140
141
  return arr
142
}
143
144
export function getFiles(folder, flatten = false, level, extensions = /(.*?)/, inversePattern = false) {
145
146
  var arr = []
0 ignored issues
show
Unused Code introduced by
The assignment to variable arr seems to be never used. Consider removing it.
Loading history...
147
  arr = cmsData.file.read(
148
    folder.replace(/\/$/, ''),
149
    folder.replace(/\/$/, ''), 
150
    'files', 
151
    flatten, 
152
    extensions, 
153
    level, 
154
    0, 
155
    inversePattern
156
  )
157
158
  return arr
159
}
160
161
export function getFilesByType(pathFile, type = null) {
162
  try {
163
    var directory = fse.lstatSync(pathFile)
164
    if (!directory.isDirectory()) {
165
      mkdirp.sync(pathFile)
0 ignored issues
show
Bug introduced by
The variable mkdirp seems to be never declared. If this is a global, consider adding a /** global: mkdirp */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
166
    }
167
  } catch (e) {
168
    mkdirp.sync(pathFile)
169
  }
170
  var files = cmsData.file.getFiles(pathFile, true, 20, new RegExp(`.${config.files.templates.extension}`))
171
172
  var result = []
173
174
  Array.prototype.forEach.call(files, (file) => {
175
    var val = cmsData.fileAttr.get(file.path).s
176
    if(type === null || val === type) result.push(file)
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
177
  })
178
  return result
179
}
180
181
export function read(base, dirName, type, flatten, extensions = /(.*?)/, max = 99, current = 0, inversePattern = false) {
182
  var arr = []
183
  var level = fse.readdirSync(dirName)
184
  var fileCurrentLevel = []
185
  let assets = config.files.templates.assets
186
187
  for (var i = 0; i < level.length; i++) {
188
    var pathLevel = dirName + '/' + level[i]
189
    var isFolder = true
190
    try {
191
      var directory = fse.lstatSync(pathLevel)
192
      if (!directory.isDirectory()) {
193
        isFolder = false
194
      }
195
    } catch (e) {
196
      isFolder = false
197
    }
198
    var match = (isFolder) ? true : (inversePattern) ? !extensions.test(level[i]) : extensions.test(level[i])
199
    if((type === 'files' || type === null) && match) {
200
201
      if(level[i].indexOf('.') > -1) {
202
        var extension = /(\.[\s\S]*)/.exec(level[i])[0]
203
        var cleanName = cmsData.fileAttr.delete(level[i])
204
        var cleanNameNoExt = cleanName.replace(/\..+$/, '')
205
        var fileData = cmsData.fileAttr.get(level[i])
206
207
        var date
208
        if (fileData.d) {
209
          date = fileData.d
210
        }else {
211
          var stat = fse.statSync(pathLevel)
212
          date = stat.mtime
213
        }
214
        var cleanFilePath = cmsData.fileAttr.delete(pathLevel).replace(config.root, '').replace(/^\/?.+?\//, '')
215
216
        var fileDate = moment(date)
217
        var duration = moment.duration(moment(fileDate).diff(new Date())).humanize(true)
218
219
        var filePath = pathLevel.replace(config.root, '')
220
        filePath = filePath.split('/')
221
        filePath.shift()
222
        filePath = filePath.join('/')
223
        var item = {
224
          'name': level[i],
225
          'path': pathLevel,
226
          'cleanPathName': cmsData.fileAttr.delete(pathLevel),
227
          'cleanPath': pathLevel.replace(base + '/', ''),
228
          date: date,
229
          cleanDate: fileDate.format('YYYY/MM/DD HH:MM:ss'),
230
          duration: duration,
231
          cleanName: cleanName,
232
          cleanNameNoExt: cleanNameNoExt,
233
          cleanFilePath: cleanFilePath,
234
          filePath: filePath,
235
          'type': 'file',
236
          'fileType': extension
237
        }
238
239
        if(!flatten) item['folders'] = []
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
240
        arr.push(item)
241
        // push current file name into array to check if siblings folder are assets folder
242
        fileCurrentLevel.push(level[i].replace(/\..+$/, '') + assets)
243
      }
244
    }
245
    if(!fileCurrentLevel.includes(level[i]) && match) {
246
      if(isFolder) {
247
        if(!flatten) {
248
          var index = arr.push({'name': level[i], 'path': pathLevel, 'cleanPath': pathLevel.replace(base + '/', ''), 'folders': [], 'type': 'folder'}) - 1
249
          if(current < max){
250
            arr[index].folders = cmsData.file.read(base, pathLevel, type, flatten, extensions, max, current + 1, inversePattern)
251
          }
252
        }else {
253
          if(type === 'folders' || type === null) {
254
            arr.push({'name': level[i], 'path': pathLevel, 'cleanPath': pathLevel.replace(base + '/', ''), 'type': 'folder'})
255
          }
256
          if(current < max){
257
            Array.prototype.forEach.call(cmsData.file.read(base, pathLevel, type, flatten, extensions, max, current + 1, inversePattern), (files) => {
258
              arr.push(files)
259
            })
260
          }
261
        }
262
      }
263
    }
264
  }
265
266
  return arr
267
}