Completed
Push — master ( 652c21...99e276 )
by greg
10:52 queued 08:59
created

file-utils.js ➔ ???   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 19
Bugs 0 Features 0
Metric Value
c 19
b 0
f 0
nc 1
nop 0
dl 0
loc 1
cc 1
rs 10
1
import fse from 'fs-extra'
2
import dircompare from 'dir-compare'
3
import mkdirp from 'mkdirp'
4
import moment from 'moment'
5
import path from 'path'
6
import {
7
	fileAttr,
8
	FileParser,
9
	config
10
} from '../../'
11
12
export default class FileUtils {
13
14
  constructor() {}
15
16
	/**
17
	 * Prepend the path with the root path
18
	 * @param  {string} path The path to be prepended
0 ignored issues
show
Documentation Bug introduced by
The parameter path does not exist. Did you maybe mean ppath instead?
Loading history...
19
	 * @return {string}      The path prepended with the root path
20
	 */
21
  static pathWithRoot(ppath) {
22
    if(typeof ppath === 'undefined' || ppath === null || ppath === '') ppath = ''
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...
23
    return path.join(config.root, ppath.replace(config.root, '')).replace(/\/$/, '')
24
  }
25
26
	/**
27
	 * [cleanPath remove the trailing slash in the path
28
	 * @param  {string} path The path to be cleaned
0 ignored issues
show
Documentation Bug introduced by
The parameter path does not exist. Did you maybe mean cpath instead?
Loading history...
29
	 * @return {string}      The path with no trailing slash
30
	 */
31
  static cleanPath(cpath) {
32
    if(typeof cpath !== 'undefined' && cpath !== null) cpath = cpath.replace(/\/$/, '')
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...
33
    return cpath
34
  }
35
36
	/**
37
	 * concatenate strings into a path. Each string being appended with a "/"
38
	 * @param  {array} array of strings to be concatenated
0 ignored issues
show
Documentation introduced by
The parameter array does not exist. Did you maybe forget to remove this comment?
Loading history...
39
	 * @return {string} path as the result of concatenation
40
	 */
41
  static concatPath() {
42
    var cpath = ''
43
    Array.prototype.forEach.call([].slice.call(arguments), (argument) => {
44
      if(cpath !== '') argument = argument.replace(/^\//, '')
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...
45
      if(argument !== '') cpath += FileUtils.cleanPath(argument) + '/'
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...
46
    })
47
48
    cpath = FileUtils.cleanPath(cpath)
49
50
    return cpath
51
  }
52
53
	/**
54
	 * Remove the last segment of the path (ie. /the/path/to => /the/path)
55
	 * @param  {string} path the path
0 ignored issues
show
Documentation introduced by
The parameter path does not exist. Did you maybe forget to remove this comment?
Loading history...
56
	 * @return {string}      The path with the last segment removed
57
	 */
58
  static removeLast(pathRemove) {
59
60
    return pathRemove.substring(0, FileUtils.cleanPath(pathRemove).lastIndexOf('/'))
61
  }
62
63
	/**
64
	 * Replace the extension in the path (ie. /the/path/to/file.txt => /the/path/to/file.json)
65
	 * @param  {string} path The path
66
	 * @param  {string} ext  The extension to put as a replacement
67
	 * @return {string}      The path with the new extension
68
	 */
69
  static replaceExtension(path, ext) {
70
71
    return path.substring(0, path.lastIndexOf('.')) + '.' + ext
72
  }
73
74
	/**
75
	 * Remove the extension from the path if any
76
	 * @param  {string} path The path
77
	 * @return {string}      The path without extension
78
	 */
79
  static removeExtension(path) {
80
    if (path.lastIndexOf('.') > -1) {
81
      return path.substring(0, path.lastIndexOf('.'))
82
    }
83
    return path
84
  }
85
86
	/**
87
	 * Extract the filename from the path (ie. /the/path/to/file.json => file.json)
88
	 * @param  {string} path The path
89
	 * @return {string}      The filename extracted from the path
90
	 */
91
  static filename(path) {
92
93
    return FileUtils.cleanPath(path).substring(FileUtils.cleanPath(path).lastIndexOf('/') + 1)
94
  }
95
96
	/**
97
	 * Check if the path given coreespond to an existing file
98
	 * @param  {string}  path The path
99
	 * @return {Boolean}      Does the file exist
100
	 */
101
  static isFile(path) {
102
    try{
103
      var stat = fse.statSync(path)
0 ignored issues
show
Unused Code introduced by
The variable stat seems to be never used. Consider removing it.
Loading history...
104
105
      return true
106
    }catch(e){
107
108
      return false
109
    }
110
111
    return false
0 ignored issues
show
introduced by
This code is unreachable and can thus be removed without consequences.
Loading history...
112
  }
113
114
	/**
115
	 * Create the directory if it doesn't exist and create the json file
116
	 * @param  {string} path The path
117
	 * @param  {string} json The Json data
118
	 */
119
  static writeJson(path, json) {
120
    mkdirp(FileUtils.removeLast(path))
121
    fse.writeJsonSync(path, json, { space: 2, encoding: 'utf-8' })
122
  }
123
124
  static removeFile(file) {
125
    fse.removeSync(file)
126
  }
127
128
	/**
129
	 * Check if the string given has an extension
130
	 * @param  {string}  fileName the filename to check
131
	 * @return {Boolean}          Wether the filename has an extension or not
132
	 */
133
  static isValidFile(fileName) {
134
    var dotPosition = fileName.indexOf('.')
135
    if(dotPosition > 0) return true
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...
136
137
    return false
138
  }
139
140
	/* TODO: put this method in the right helper */
141
  static cleanTplName(pathClean) {
142
    var cleanTplName = fileAttr.delete(pathClean)
143
    cleanTplName = cleanTplName.replace(config.root, '')
144
    cleanTplName = cleanTplName.split('/')
145
    cleanTplName.shift()
146
    return cleanTplName.join('/')
147
  }
148
149
	/* TODO: Remove this method and replace it with the previous one */
150
  static cleanFilePath(pathClean) {
151
    var cleanFilePath = fileAttr.delete(pathClean)
152
    cleanFilePath = cleanFilePath.replace(config.root, '')
153
    cleanFilePath = cleanFilePath.split('/')
154
    cleanFilePath.shift()
155
    return cleanFilePath.join('/')
156
  }
157
158
	
159
	/* TODO: put this method in the right helper */
160
  static getFilePath(pathFile) {
161
    var res = null
162
    if(typeof pathFile !== 'undefined' && pathFile !== null && pathFile !== '') {
163
      res = pathFile.replace(config.root)
164
      res = path.join(config.root, config.draft.url, res)
165
    }
166
    return res
167
  }
168
169
  /* TODO: refactor this method as Facade method to a method adding a fragment in a path */
170
  static getTemplatePath(pathTemplate) {
171
    if (pathTemplate.indexOf('.') === -1) { // no extension add one
172
      pathTemplate = `${pathTemplate}.${config.files.templates.extension}`
173
    }
174
175
    var res = null
176
    if(typeof pathTemplate !== 'undefined' && pathTemplate !== null && pathTemplate !== '') {
177
      res = pathTemplate.replace(config.root)
178
      res = path.join(config.root, config.templates.url, res)
179
    }
180
    return res
181
  }
182
183
  /**
184
   * This method checks that the path leads to a file and return the content as UTF-8 content
185
   * @param  {string} path The path
186
   * @return {string}      The content of the UTF-8 file
187
   */
188
  static getFileContent(path) {
189
    var res = null
190
    if(typeof path !== 'undefined' && path !== null && path !== '') {
191
      if (FileUtils.isFile(path)) {
192
        res = fse.readFileSync(path, 'utf8')
193
      }
194
    }
195
    return res
196
  }
197
198
  /* TODO: put this method in its right helper */
199
  static deleteOlderRevisionByType(fileName, type) {
200
    var folder = fileName.split('/')
201
    var file = folder.pop()
202
    var extension = file.replace(/.*?\./, '')
203
    folder = folder.join('/')
204
    var stat = fse.statSync(folder)
205
    if(stat){
206
      var files = FileParser.getFiles(folder, true, 1, new RegExp('\\.' + extension))
207
      files.forEach(function (fileItem) {
208
        var fname = fileAttr.delete(fileItem.cleanPath)
209
        var ftype = fileAttr.get(fileItem.cleanPath).s
210
        if(fname === file && ftype === type){
211
          var fileDraft = fileItem.path.replace(/-abe-./, '-abe-d')
212
          FileParser.removeFile(fileItem.path, FileParser.changePathEnv(fileItem.path, config.data.url).replace(new RegExp('\\.' + extension), '.json'))
213
          FileParser.removeFile(fileDraft, FileParser.changePathEnv(fileDraft, config.data.url).replace(new RegExp('\\.' + extension), '.json'))
214
        }
215
      })
216
    }
217
  }
218
  
219
  /* TODO: put this method in its right helper */
220
  static getFilesMerged(files) {
221
    var merged = {}
222
    var arMerged = []
223
		
224
    Array.prototype.forEach.call(files, (file) => {
225
      var cleanFilePath = file.cleanFilePath
226
227
      var fileStatusIsPublish = fileAttr.get(file.cleanPath)
228
      if(typeof fileStatusIsPublish.s !== 'undefined' && fileStatusIsPublish.s !== null && file.abe_meta.status === 'publish') {
229
        file.abe_meta.status = 'draft'
230
      }
231
232
      file.html = path.join('/', file.filePath.replace(/\.json/, `.${config.files.templates.extension}`))
233
      if (file.abe_meta.status === 'publish') {
234
        file.htmlPath = path.join(config.root, config.publish.url, path.join('/', file.filePath.replace(/\.json/, `.${config.files.templates.extension}`)))
235
      }else {
236
        file.htmlPath = path.join(config.root, config.draft.url, path.join('/', file.filePath.replace(/\.json/, `.${config.files.templates.extension}`)))
237
      }
238
239
      if(typeof merged[cleanFilePath] === 'undefined' || merged[cleanFilePath] === null) {
240
        merged[cleanFilePath] = {
241
          name: fileAttr.delete(file.name)
242
					, path: fileAttr.delete(file.path)
243
					, html: fileAttr.delete(path.join('/', file.filePath.replace(/\.json/, `.${config.files.templates.extension}`)))
244
					, htmlPath: path.join(config.root, config.publish.url, path.join('/', fileAttr.delete(file.filePath.replace(/\.json/, `.${config.files.templates.extension}`))))
245
					, cleanPathName: file.cleanPathName
246
					, cleanPath: file.cleanPath
247
					, cleanName: file.cleanName
248
					, cleanNameNoExt: file.cleanNameNoExt
249
					, cleanFilePath: file.cleanFilePath
250
					, filePath: fileAttr.delete(file.filePath)
251
					, revisions: []
252
        }
253
      }
254
255
      merged[cleanFilePath].revisions.push(JSON.parse(JSON.stringify(file)))
256
    })
257
258
    // return merged
259
    Array.prototype.forEach.call(Object.keys(merged), (key) => {
260
      var revisions = merged[key].revisions
261
      revisions.sort(FileParser.predicatBy('date', -1))
262
      if(typeof revisions[0] !== 'undefined' && revisions[0] !== null) {
263
        merged[key].date = revisions[0].date
264
      }
265
266
      Array.prototype.forEach.call(revisions, (revision) => {
267
				
268
        var status = revision.abe_meta.status
269
270
        if (status === 'publish') {
271
          merged[key][status] = revision
272
        }else {
273
          merged[key][status] = {}
274
        }
275
        merged[key][status].path = revision.path
276
        merged[key][status].html = revision.html
277
        merged[key][status].htmlPath = revision.htmlPath
278
        merged[key][status].date = new Date(revision.date)
279
        merged[key][status].link = revision.abe_meta.link
280
      })
281
282
      merged[key].revisions = revisions
283
284
      merged[key].date = revisions[0].date
285
      merged[key].cleanDate = revisions[0].cleanDate
286
      merged[key].duration = revisions[0].duration
287
      merged[key].abe_meta = revisions[0].abe_meta
288
289
      arMerged.push(merged[key])
290
    })
291
292
    return arMerged
293
  }
294
295
}
296