Completed
Push — master ( 5f12f5...5ff82a )
by
unknown
01:50
created

src/cli/cms/templates/template.js   F

Complexity

Total Complexity 73
Complexity/F 2.15

Size

Lines of Code 335
Function Count 34

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 0
wmc 73
nc 1
mnd 3
bc 61
fnc 34
dl 0
loc 335
rs 3.9761
bpm 1.7941
cpm 2.1469
noi 6
c 0
b 0
f 0

16 Functions

Rating   Name   Duplication   Size   Complexity  
A template.js ➔ getTemplatesAndPartials 0 11 1
A template.js ➔ addOrder 0 21 3
A template.js ➔ includePartials 0 17 1
C template.js ➔ getVariablesInWhere 0 30 8
B template.js ➔ translate 0 41 3
B template.js ➔ getTemplate 0 26 3
B template.js ➔ recurseWhereVariables 0 22 4
A template.js ➔ getAbeImport 0 10 2
A template.js ➔ execRequestColumns 0 22 1
A template.js ➔ getTemplatesTexts 0 18 1
A template.js ➔ getAbeRequestWhereKeysFromTemplates 0 12 1
A template.js ➔ setAbeSlugDefaultValueIfDoesntExist 0 8 3
A template.js ➔ getAbeSlugFromTemplates 0 10 1
A template.js ➔ setAbePrecontribDefaultValueIfDoesntExist 0 8 3
B template.js ➔ getAbePrecontribFromTemplates 0 26 1
A template.js ➔ getStructureAndTemplates 0 18 1

How to fix   Complexity   

Complexity

Complex classes like src/cli/cms/templates/template.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 fse from 'fs-extra'
2
import {Promise} from 'bluebird'
3
import path from 'path'
4
import {
5
  config,
6
  coreUtils,
7
  cmsData,
8
  abeExtend
9
} from '../../'
10
11
export function getTemplatesAndPartials(templatesPath) {
12
  var p = new Promise((resolve) => {
13
    const extension = '.' + config.files.templates.extension
14
    return coreUtils.file.getFilesAsync(templatesPath, true, extension)
15
      .then(function(files){
16
        return resolve(files)
17
      })
18
  })
19
20
  return p
21
}
22
23
export function addOrder(text) {
24
  var regAbe = /{{abe[\S\s].*?key=['|"]([\S\s].*?['|"| ]}})/g
25
  var matches = text.match(regAbe)
26
  var order = 0
27
  
28
  if(typeof matches !== 'undefined' && matches !== null){
29
    Array.prototype.forEach.call(matches, (match) => {
30
      if(typeof match !== 'undefined' && match !== null) {
31
        
32
        var orderAttr = cmsData.regex.getAttr(match, 'order')
33
34
        if(typeof orderAttr === 'undefined' || orderAttr === null || orderAttr === '') {
35
          var matchOrder = match.replace(/\}\}$/, ` order='${order}'}}`)
36
          text = text.replace(match, matchOrder)
37
        }
38
        order++
39
      }
40
    })
41
  }
42
  return text
43
}
44
45
export function getAbeImport(text) {
46
  var partials = []
47
  let listReg = /({{abe.*?type=[\'|\"]import.*?}})/g
48
  var match
49
  while (match = listReg.exec(text)) {
50
    partials.push(match[0])
51
  }
52
53
  return partials
54
}
55
56
export function includePartials(text) {
57
  var abeImports = getAbeImport(text)
58
59
  Array.prototype.forEach.call(abeImports, (abeImport) => {
60
    var obj = cmsData.attributes.getAll(abeImport, {})
61
62
    var file = obj.file
63
    var partial = ''
64
    file = path.join(config.root, config.partials, file)
65
    if(coreUtils.file.exist(file)) {
66
      partial = includePartials(fse.readFileSync(file, 'utf8'))
67
    }
68
    text = text.replace(cmsData.regex.escapeTextToRegex(abeImport, 'g'), partial)
69
  })
70
71
  return text
72
}
73
74
function translate(text) {
75
  var importReg = /({{abe.*type=[\'|\"]translate.*}})/g
76
77
  var matches = text.match(importReg)
78
  
79
  if(typeof matches !== 'undefined' && matches !== null) {
80
    Array.prototype.forEach.call(matches, (match) => {
81
      var splitedMatches = match.split('{{abe ')
82
83
      Array.prototype.forEach.call(splitedMatches, (splitedMatch) => {
84
        var currentMatch = `{{abe ${splitedMatch}`
85
        if(/({{abe.*type=[\'|\"]translate.*}})/.test(currentMatch)) {
86
          var locale = cmsData.regex.getAttr(currentMatch, 'locale')
87
          var source = cmsData.regex.getAttr(currentMatch, 'source')
88
89
          if (locale.indexOf('{{') === -1) {
90
            locale = `'${locale}'`
91
          }else {
92
            locale = locale.replace(/\{\{(.*?)\}\}/, '$1')
93
          }
94
95
          if (source.indexOf('{{') === -1) {
96
            source = `'${source.replace(/'/g, '\\\'')}'`
97
          }else {
98
            source = source.replace(/\{\{(.*?)\}\}/, '$1')
99
          }
100
101
          // var replace = `{{{i18nAbe ${locale} ${source}}}}`
102
          var replace = currentMatch.replace('{{abe', '{{i18nAbe')
103
          replace = replace.replace(/locale=['|"].*?['|"]/, locale)
104
          replace = replace.replace(/source=['|"].*?['|"]/, source)
105
          replace = replace.replace(/{{i18nAbe.*?}}/, `{{{i18nAbe ${locale} ${source}}}}`)
106
107
          text = text.replace(cmsData.regex.escapeTextToRegex(currentMatch, 'g'), replace)
108
        }
109
      })
110
    })
111
  }
112
113
  return text
114
}
115
116
export function getTemplate (file) {
117
  var text = ''
118
119
  // HOOKS beforeGetTemplate
120
  file = abeExtend.hooks.instance.trigger('beforeGetTemplate', file)
121
122
  file = file.replace(path.join(config.root, config.templates.url), '')
123
  file = file.replace(config.root, '')
124
  if (file.indexOf('.') > -1) {
125
    file = file.replace(/\..+$/, '')
126
  }
127
  file = path.join(config.root, config.templates.url, file + '.' + config.files.templates.extension)
128
  if(coreUtils.file.exist(file)) {
129
    text = fse.readFileSync(file, 'utf8')
130
    text = includePartials(text)
131
    text = translate(text)
132
    text = addOrder(text)
133
  }else {
134
    text = `[ ERROR ] template ${file + '.' + config.files.templates.extension} doesn't exist anymore`
135
  }
136
137
  // HOOKS afterGetTemplate
138
  text = abeExtend.hooks.instance.trigger('afterGetTemplate', text)
139
140
  return text
141
}
142
143
export function getVariablesInWhere(where) {
144
  var ar = []
145
146
  if(where.left.column.indexOf('{{') > -1) {
147
    ar.push(where.left.column.replace(/\{\{(.*?)\}\}/, '$1'))
148
  }
149
  else{
150
    ar.push(where.left.column)
151
  }
152
153
  if (where.right.value) {
154
    if (typeof where.right.value === 'string') {
155
      if(where.right.value && where.right.value.indexOf('{{') > -1) {
156
        ar.push(where.right.value.replace(/\{\{(.*?)\}\}/, '$1'))
157
      }
158
    }else {
159
      where.right.value.forEach(function (value) {
160
        if(value.column.indexOf('{{') > -1) {
161
          ar.push(value.column.replace(/\{\{(.*?)\}\}/, '$1'))
162
        }
163
      })
164
    }
165
  }
166
167
  if(where.right.column && where.right.column.indexOf('{{') > -1) {
168
    ar.push(where.right.column.replace(/\{\{(.*?)\}\}/, '$1'))
169
  }
170
171
  return ar
172
}
173
174
/**
175
 * Get columns and where.left ids of a select statement
176
 *
177
 * select title, image from ../ where template=""
178
 *
179
 * return [title, image, template]
180
 * 
181
 * @param  {Array} templatesList ["article.html", "other.html"]
0 ignored issues
show
Documentation introduced by
The parameter templatesList does not exist. Did you maybe forget to remove this comment?
Loading history...
182
 * @return {Promise}
183
 */
184
export function recurseWhereVariables (where) {
185
  var ar = []
0 ignored issues
show
Unused Code introduced by
The assignment to variable ar seems to be never used. Consider removing it.
Loading history...
186
  var arLeft
187
  var arRight
188
  switch(where.operator) {
189
  case 'AND':
190
    arLeft = recurseWhereVariables(where.left)
191
    arRight = recurseWhereVariables(where.right)
192
    return arLeft.concat(arRight)
193
    break
0 ignored issues
show
Unused Code introduced by
This break statement is unnecessary and may be removed.
Loading history...
194
  case 'OR':
195
    arLeft = recurseWhereVariables(where.left)
196
    arRight = recurseWhereVariables(where.right)
197
    return arLeft.concat(arRight)
198
    break
0 ignored issues
show
Unused Code introduced by
This break statement is unnecessary and may be removed.
Loading history...
199
  default:
200
    ar = getVariablesInWhere(where)
201
    break
202
  }
203
204
  return ar
205
}
206
207
export function getTemplatesTexts(templatesList) {
208
  var templates = []
209
  var p = new Promise((resolve) => {
210
    Array.prototype.forEach.call(templatesList, (file) => {
211
      var template = fse.readFileSync(file, 'utf8')
212
      template = includePartials(template)
213
      var name = file.replace(path.join(config.root, config.templates.url, path.sep), '').replace(`.${config.files.templates.extension}`, '')
214
      templates.push({
215
        name: name,
216
        path: file,
217
        template: template
218
      })
219
    })
220
    resolve(templates)
221
  })
222
223
  return p
224
}
225
226
export function execRequestColumns(tpl) {
227
  var ar = []
228
  var matches = cmsData.regex.getTagAbeTypeRequest(tpl)
229
  Array.prototype.forEach.call(matches, (match) => {
230
    var obj = cmsData.attributes.getAll(match[0], {})
231
    var type = cmsData.sql.getSourceType(obj.sourceString)
232
    switch (type) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
233
    case 'request':
234
      var request = cmsData.sql.handleSqlRequest(obj.sourceString, {})
235
      if(typeof request.columns !== 'undefined' && request.columns !== null) {
236
        Array.prototype.forEach.call(request.columns, (column) => {
237
          ar.push(column)
238
        })
239
      }
240
      if(typeof request.where !== 'undefined' && request.where !== null) {
241
        ar = ar.concat(recurseWhereVariables(request.where))
242
      }
243
    }
244
  })
245
246
  return ar
247
}
248
249
export function getAbeRequestWhereKeysFromTemplates(templatesList) {
250
  var whereKeys = []
251
  var p = new Promise((resolve) => {
252
    Array.prototype.forEach.call(templatesList, (file) => {
253
      whereKeys = whereKeys.concat(execRequestColumns(file.template))
254
    })
255
    whereKeys = whereKeys.filter(function (item, pos) {return whereKeys.indexOf(item) == pos})
256
    resolve(whereKeys)
257
  })
258
259
  return p
260
}
261
262
export function setAbeSlugDefaultValueIfDoesntExist(templateText) {
263
  var matches = cmsData.regex.getTagAbeWithType(templateText, 'slug')
264
  if(matches == null || matches[0] == null) {
265
    templateText = `{{abe type="slug" source="{{name}}"}}\n${templateText}`
266
  }
267
268
  return templateText
269
}
270
271
export function getAbeSlugFromTemplates(templatesList) {
272
  var slugs = {}
273
  Array.prototype.forEach.call(templatesList, (file) => {
274
    var templateText = setAbeSlugDefaultValueIfDoesntExist(file.template)
275
    var matchesSlug = cmsData.regex.getTagAbeWithType(templateText, 'slug')
276
    var obj = cmsData.attributes.getAll(matchesSlug[0], {})
277
    slugs[file.name] = obj.sourceString
278
  })
279
  return slugs
280
}
281
282
export function setAbePrecontribDefaultValueIfDoesntExist(templateText) {
283
  var matches = cmsData.regex.getTagAbeWithTab(templateText, 'slug')
284
  if(matches == null || matches[0] == null) {
285
    templateText = `{{abe type='text' key='name' desc='Name' required="true" tab="slug" visible="false"}}\n${templateText}`
286
  }
287
288
  return templateText
289
}
290
291
export function getAbePrecontribFromTemplates(templatesList) {
292
  var fields = []
293
  var precontributionTemplate = ''
294
  Array.prototype.forEach.call(templatesList, (file) => {
295
    var slugMatch = cmsData.regex.getTagAbeWithType(file.template, 'slug')
296
    var templateText = file.template
297
    if(slugMatch == null || slugMatch[0] == null) {
298
      templateText = setAbePrecontribDefaultValueIfDoesntExist(file.template)
299
    }
300
301
    var matchesTabSlug = cmsData.regex.getTagAbeWithTab(templateText, 'slug')
302
    Array.prototype.forEach.call(matchesTabSlug, (match) => {
303
      fields.push(cmsData.attributes.getAll(match, {}))
304
      var tag = match.replace(/\}\}$/, ' precontribTemplate="' + file.name + '"}}')
305
      tag = tag.replace(/(key=[\'|\"])(.*?)([\'|\"])/, '$1/' + file.name + '/$2$3')
306
      precontributionTemplate += `${tag}\n`
307
    })
308
  })
309
310
  precontributionTemplate = addOrder(precontributionTemplate)
311
312
  return {
313
    fields: fields,
314
    template: precontributionTemplate
315
  }
316
}
317
318
export function getStructureAndTemplates() {
319
  const pathStructure = path.join(config.root, config.structure.url)
320
  const pathTemplates = path.join(config.root, config.templates.url)
321
  const extension = '.' + config.files.templates.extension
322
  let result = {'structure': [], 'templates': []}
323
324
  result.structure = coreUtils.file.getFoldersSync(pathStructure, true)
325
  let templatePaths = coreUtils.file.getFilesSync(pathTemplates, true, extension)
326
  Array.prototype.forEach.call(templatePaths, (templatePath) => {
327
    let additionalPath = path.dirname(templatePath).replace(pathTemplates,'')
328
    if(additionalPath !== '') additionalPath = additionalPath.substring(1)
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...
329
    let name = path.join(additionalPath,path.basename(templatePath,extension))
330
    let template = {'path':templatePath, 'name':name}
331
    result.templates.push(template)
332
  })
333
334
  return result
335
}