Completed
Push — master ( 33a525...eb0f8c )
by greg
17s
created

template.js ➔ translate   B

Complexity

Conditions 3
Paths 2

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
c 2
b 0
f 0
nc 2
nop 1
dl 0
loc 28
rs 8.8571

1 Function

Rating   Name   Duplication   Size   Complexity  
A template.js ➔ ... ➔ ??? 0 18 1
1
import fse from 'fs-extra'
2
import {Promise} from 'bluebird'
3
import path from 'path'
4
import {
5
  config,
6
  Manager,
7
  coreUtils,
8
  cmsData,
9
  abeExtend,
10
  cmsTemplates
11
} from '../../'
12
import * as sourceAttr from '../../cms/editor/handlebars/sourceAttr'
13
14
export function getTemplatesAndPartials(templatesPath, partialsPath) {
15
  let allFiles = []
16
  var p = new Promise(resolve => {
17
    const extension = '.' + config.files.templates.extension
18
    return coreUtils.file
19
      .getFilesAsync(templatesPath, true, extension)
20
      .then(function(files) {
21
        allFiles = allFiles.concat(files)
22
        return coreUtils.file
23
          .getFilesAsync(partialsPath, true, extension)
24
          .then(function(files) {
25
            allFiles = allFiles.concat(files)
26
            return resolve(allFiles)
27
          })
28
      })
29
  })
30
31
  return p
32
}
33
34
export function addOrder(text) {
35
  var regAbe = /{{abe[\S\s].*?key=['|"]([\S\s].*?['|"| ]}})/g
36
  var matches = text.match(regAbe)
37
38
  if (typeof matches !== 'undefined' && matches !== null) {
39
    var orderTab = []
40
    var arrayKey = []
41
    var max = 0
42
    var negIndex = -1
43
44
    // We create an array of keys/order and put -1 for keys without order
45
    Array.prototype.forEach.call(matches, match => {
46
      if (typeof match !== 'undefined' && match !== null) {
47
        var orderAttr = cmsData.regex.getAttr(match, 'order')
48
        var keyAttr = cmsData.regex.getAttr(match, 'key')
49
        if (
50
          typeof orderAttr === 'undefined' ||
51
          orderAttr === null ||
52
          orderAttr === ''
53
        ) {
54
          orderTab.push({key: keyAttr, order: negIndex})
55
          negIndex = negIndex - 1
56
        } else {
57
          max = Math.max(parseInt(orderAttr), max)
58
          orderTab.push({key: keyAttr, order: orderAttr})
59
        }
60
      }
61
    })
62
63
    // We sort the array
64
    orderTab.sort(coreUtils.sort.predicatBy('order', -1))
65
66
    // And increment the not ordered ones beginning with the last order found + 1
67
    Array.prototype.forEach.call(orderTab, obj => {
68
      if (obj.order < 0) {
69
        max = max + 1
70
        arrayKey[obj.key] = max
71
      } else {
72
        arrayKey[obj.key] = parseInt(obj.order)
73
      }
74
    })
75
76
    // Then we put order attribute to each abe tag not ordered
77
    Array.prototype.forEach.call(matches, match => {
78
      if (typeof match !== 'undefined' && match !== null) {
79
        var orderAttr = cmsData.regex.getAttr(match, 'order')
80
        var keyAttr = cmsData.regex.getAttr(match, 'key')
81
        if (
82
          typeof orderAttr === 'undefined' ||
83
          orderAttr === null ||
84
          orderAttr === ''
85 View Code Duplication
        ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
86
          var matchOrder = match.replace(
87
            /\}\}$/,
88
            ` order='${arrayKey[keyAttr]}'}}`
89
          )
90
          text = text.replace(match, matchOrder)
91
        }
92
      }
93
    })
94
  }
95
96
  return text
97
}
98
99
export function getAbeImport(text) {
100
  var partials = []
101
  let listReg = /({{abe.*type=[\'|\"]import.*}})/g
102
  var match
103
  while ((match = listReg.exec(text))) {
104
    partials.push(match[0])
105
  }
106 View Code Duplication
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
107
  return partials
108
}
109
110
/**
111
 * it will include recursively each encountered type=import
112
 * and proceed to a foreach when the file={{some[]}} is an array of values
113
 * @param  {[type]} text [description]
114
 * @param  {[type]} json [description]
115
 * @return {[type]}      [description]
116
 */
117
export function includePartials(text, json) {
118
  var abeImports = cmsTemplates.template.getAbeImport(text)
119
  var duplicateImports = duplicateImports || []
0 ignored issues
show
Bug introduced by
The variable duplicateImports seems to be never initialized.
Loading history...
120
121
  Array.prototype.forEach.call(abeImports, abeImport => {
122
    var obj = cmsData.attributes.getAll(abeImport, {})
123
124
    var file = obj.file
125
    var partial = ''
126
    if (file.charAt(0) == '/') {
127
      file = path.join(config.root, file)
128
    } else {
129
      file = path.join(Manager.instance.pathPartials, file)
130
    }
131
132
    file = cmsData.attributes.getValueFromAttribute(file, json)
133
    if (Object.prototype.toString.call(file) === '[object Array]') {
134
      Array.prototype.forEach.call(file, f => {
135
        if (coreUtils.file.exist(f)) {
136
          if (duplicateImports[f] != null) {
137
            var tmpFile = fse.readFileSync(f, 'utf8')
138
            var regAbe = /{{abe .*key=[\'|\"](.*?)[\'|\"].*}}/g
139
            var matches = tmpFile.match(regAbe)
0 ignored issues
show
Unused Code introduced by
The variable matches seems to be never used. Consider removing it.
Loading history...
140
            var match
141
            while ((match = regAbe.exec(tmpFile)) !== null) {
142
              if (match[1] != null) {
143
                tmpFile = tmpFile.replace(
144
                  match[0],
145
                  match[0].replace(
146
                    match[1],
147
                    match[1] + '_' + duplicateImports[f]
148
                  )
149
                )
150
                tmpFile = tmpFile.replace(
151
                  new RegExp(`\{\{${match[1]}`, 'g'),
152
                  '{{' + match[1] + '_' + duplicateImports[f]
153
                )
154
              }
155
            }
156
            duplicateImports[f] += 1
157
            partial += cmsTemplates.template.includePartials(tmpFile, json)
158
          } else {
159
            duplicateImports[f] = 1
160
            partial += cmsTemplates.template.includePartials(
161
              fse.readFileSync(f, 'utf8'),
162
              json
163
            )
164
          }
165
        }
166
      })
167
    } else {
168
      if (coreUtils.file.exist(file)) {
169
        if (duplicateImports[file] != null) {
170
          var tmpFile = fse.readFileSync(file, 'utf8')
171
          var regAbe = /{{abe .*key=[\'|\"](.*?)[\'|\"].*}}/g
172
          var match
173
          while ((match = regAbe.exec(tmpFile)) !== null) {
174
            if (match[1] != null) {
175
              tmpFile = tmpFile.replace(
176
                match[0],
177
                match[0].replace(
178
                  match[1],
179
                  match[1] + '_' + duplicateImports[file]
180
                )
181
              )
182
              tmpFile = tmpFile.replace(
183
                new RegExp(`\{\{${match[1]}`, 'g'),
184
                '{{' + match[1] + '_' + duplicateImports[file]
185
              )
186
            }
187
          }
188
189
          duplicateImports[file] += 1
190
          partial = cmsTemplates.template.includePartials(tmpFile, json)
191
        } else {
192
          duplicateImports[file] = 1
193
          partial = cmsTemplates.template.includePartials(
194
            fse.readFileSync(file, 'utf8'),
195
            json
196
          )
197
        }
198
      }
199
    }
200
    text = text.replace(cmsData.regex.escapeTextToRegex(abeImport), partial)
201
  })
202
203
  return text
204
}
205
206
export function translate(text) {
207
  var importReg = /({{abe.*type=[\'|\"]translate.*}})/g
208
209
  var matches = text.match(importReg)
210
211
  if (typeof matches !== 'undefined' && matches !== null) {
212
    Array.prototype.forEach.call(matches, match => {
213
      var splitedMatches = match.split('{{abe ')
214
215
      Array.prototype.forEach.call(splitedMatches, splitedMatch => {
216
        var currentMatch = `{{abe ${splitedMatch}`
217
        if (/({{abe.*type=[\'|\"]translate.*}})/.test(currentMatch)) {
218
          var locale = cmsData.regex.getAttr(currentMatch, 'locale')
219
          var source = cmsData.regex.getAttr(currentMatch, 'source')
220
221
          var replace = `{{{i18nAbe "${locale}" "${source}" this}}}`
222
223
          text = text.replace(
224
            cmsData.regex.escapeTextToRegex(currentMatch, 'g'),
225
            replace
226
          )
227
        }
228
      })
229
    })
230
  }
231
232
  return text
233
}
234
235
export function getTemplate(file, json = {}) {
236
  var text = ''
237
238
  // HOOKS beforeGetTemplate
239
  file = abeExtend.hooks.instance.trigger('beforeGetTemplate', file)
240
241
  file = file.replace(Manager.instance.pathTemplates, '')
242
  file = file.replace(config.root, '')
243
  if (file.indexOf('.') > -1) {
244
    file = file.replace(/\..+$/, '')
245
  }
246
  file = path.join(
247
    Manager.instance.pathTemplates,
248
    file + '.' + config.files.templates.extension
249
  )
250
  if (coreUtils.file.exist(file)) {
251
    text = fse.readFileSync(file, 'utf8')
252
    text = cmsTemplates.template.includePartials(text, json)
253
    text = cmsTemplates.template.translate(text)
254
    text = cmsTemplates.template.addOrder(text)
255
  } else {
256
    text = `[ ERROR ] template ${file} doesn't exist anymore`
257
  }
258
259
  // HOOKS afterGetTemplate
260
  text = abeExtend.hooks.instance.trigger('afterGetTemplate', text)
261
262
  return text
263
}
264
265
export function getVariablesInWhere(where) {
266
  var ar = []
267
268
  if (where.left.column.indexOf('{{') > -1) {
269
    ar.push(where.left.column.replace(/\{\{(.*?)\}\}/, '$1'))
270
  } else {
271
    ar.push(where.left.column)
272
  }
273
274
  if (where.right.value) {
275
    if (typeof where.right.value === 'string') {
276
      if (where.right.value && where.right.value.indexOf('{{') > -1) {
277
        ar.push(where.right.value.replace(/\{\{(.*?)\}\}/, '$1'))
278
      }
279
    } else {
280
      where.right.value.forEach(function(value) {
281
        if (value.column.indexOf('{{') > -1) {
282
          ar.push(value.column.replace(/\{\{(.*?)\}\}/, '$1'))
283
        }
284
      })
285
    }
286
  }
287
288
  if (where.right.column && where.right.column.indexOf('{{') > -1) {
289
    ar.push(where.right.column.replace(/\{\{(.*?)\}\}/, '$1'))
290
  }
291
292
  return ar
293
}
294
295
/**
296
 * Get columns and where.left ids of a select statement
297
 *
298
 * select title, image from ../ where template=""
299
 *
300
 * return [title, image, template]
301
 * 
302
 * @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...
303
 * @return {Promise}
304
 */
305
export function recurseWhereVariables(where) {
306
  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...
307
  var arLeft
308
  var arRight
309
  switch (where.operator) {
310
    case 'AND':
311
      arLeft = cmsTemplates.template.recurseWhereVariables(where.left)
312
      arRight = cmsTemplates.template.recurseWhereVariables(where.right)
313
      return arLeft.concat(arRight)
314
      break
0 ignored issues
show
Unused Code introduced by
This break statement is unnecessary and may be removed.
Loading history...
315
    case 'OR':
316
      arLeft = cmsTemplates.template.recurseWhereVariables(where.left)
317
      arRight = cmsTemplates.template.recurseWhereVariables(where.right)
318
      return arLeft.concat(arRight)
319
      break
0 ignored issues
show
Unused Code introduced by
This break statement is unnecessary and may be removed.
Loading history...
320
    default:
321
      ar = getVariablesInWhere(where)
322
      break
323
  }
324
325
  return ar
326
}
327
328
export function getTemplatesTexts(templatesList, json) {
329
  var templates = []
330
  var p = new Promise(resolve => {
331
    Array.prototype.forEach.call(templatesList, file => {
332
      var template = fse.readFileSync(file, 'utf8')
333
      template = cmsTemplates.template.includePartials(template, json)
334
      var name = file
335
        .replace(path.join(Manager.instance.pathTemplates, path.sep), '')
336
        .replace(`.${config.files.templates.extension}`, '')
337
      templates.push({
338
        name: name,
339
        path: file,
340
        template: template
341
      })
342
    })
343
    resolve(templates)
344
  })
345
346
  return p
347
}
348
349
export function execRequestColumns(tpl) {
350
  var ar = []
351
  var matches = cmsData.regex.getTagAbeTypeRequest(tpl)
352
  Array.prototype.forEach.call(matches, match => {
353
    var obj = cmsData.attributes.getAll(match[0], {})
354
    var type = cmsData.sql.getSourceType(obj.sourceString)
355
    switch (type) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
356
      case 'request':
357
        var request = cmsData.sql.handleSqlRequest(obj.sourceString, {})
358
        if (
359
          typeof request.columns !== 'undefined' &&
360
          request.columns !== null
361
        ) {
362
          Array.prototype.forEach.call(request.columns, column => {
363
            ar.push(column)
364
          })
365
        }
366
        if (typeof request.where !== 'undefined' && request.where !== null) {
367
          ar = ar.concat(
368
            cmsTemplates.template.recurseWhereVariables(request.where)
369
          )
370
        }
371
    }
372
  })
373
374
  return ar
375
}
376
377
export function getAbeRequestWhereKeysFromTemplates(templatesList) {
378
  var whereKeys = []
379
  var p = new Promise(resolve => {
380
    Array.prototype.forEach.call(templatesList, file => {
381
      whereKeys = whereKeys.concat(
382
        cmsTemplates.template.execRequestColumns(file.template)
383
      )
384
    })
385
    whereKeys = whereKeys.filter(function(item, pos) {
386
      item = item.split('.')[0].split('[')[0]
387
      return whereKeys.indexOf(item) == pos
388
    })
389
    resolve(whereKeys)
390
  })
391
392
  return p
393
}
394
395
export function setAbeSlugDefaultValueIfDoesntExist(templateText) {
396
  var matches = cmsData.regex.getTagAbeWithType(templateText, 'slug')
397
  if (matches == null || matches[0] == null) {
398
    templateText = `{{abe type="slug" source="{{name}}"}}\n${templateText}`
399
  }
400
401
  return templateText
402
}
403
404
export function getAbeSlugFromTemplates(templatesList) {
405
  var slugs = {}
406
  Array.prototype.forEach.call(templatesList, file => {
407
    var templateText = cmsTemplates.template.setAbeSlugDefaultValueIfDoesntExist(
408
      file.template
409
    )
410
    var matchesSlug = cmsData.regex.getTagAbeWithType(templateText, 'slug')
411
    var obj = cmsData.attributes.getAll(matchesSlug[0], {})
412
    slugs[file.name] = obj.sourceString
413
  })
414
  return slugs
415
}
416
417
/**
418
 * if there is no abe tab='slug' in the template, add a default abe tag
419
 * @param {[type]} templateText [description]
420
 */
421
export function setAbePrecontribDefaultValueIfDoesntExist(templateText) {
422
  var matches = cmsData.regex.getTagAbeWithTab(templateText, 'slug')
423
  if (matches == null || matches[0] == null) {
424
    templateText = `{{abe type='text' key='name' desc='Name' required="true" tab="slug" visible="false"}}\n${templateText}`
425
  }
426
427
  return templateText
428
}
429
430
/**
431
 * Lists all templates, in each template:
432
 * if no tab='slug' replaces the template with default tag {{abe type='text' key='name'...}}
433
 * then removes all abe tags (but the tab='slug' ones)
434
 * then adds 'precontribTemplate' with the template name as an attribute to tab='slug' tags
435
 * @param  {Array} templatesList [description]
436
 * @return {Array}              [description]
437
 */
438
export function getAbePrecontribFromTemplates(templatesList) {
439
  var precontributionTemplate = []
440
441
  Array.prototype.forEach.call(templatesList, file => {
442
    var templateText = cmsTemplates.template.setAbePrecontribDefaultValueIfDoesntExist(
443
      file.template
444
    )
445
    templateText = templateText.replace(
446
      /(?!.*?tab=['|"]slug)(\{\{abe.+.*\}\})/g,
447
      ''
448
    )
449
    templateText = templateText.replace(
450
      /(\{\{abe.+)(\}\})/g,
451
      `$1 precontribTemplate="${file.name}"$2`
452
    )
453
    precontributionTemplate.push(templateText)
454
  })
455
456
  return precontributionTemplate
457
}
458
459
export function getStructureAndTemplates() {
460
  const extension = '.' + config.files.templates.extension
461
  let result = {structure: [], templates: []}
462
463
  result.structure = coreUtils.file.getFoldersSync(
464
    Manager.instance.pathStructure,
465
    true
466
  )
467
  let templatePaths = coreUtils.file.getFilesSync(
468
    Manager.instance.pathTemplates,
469
    true,
470
    extension
471
  )
472
  Array.prototype.forEach.call(templatePaths, templatePath => {
473
    let additionalPath = path
474
      .dirname(templatePath)
475
      .replace(Manager.instance.pathTemplates, '')
476
    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...
477
    let name = path.join(additionalPath, path.basename(templatePath, extension))
478
    let template = {path: templatePath, name: name}
479
    result.templates.push(template)
480
  })
481
482
  return result
483
}
484