Passed
Push — master ( cc9df7...a66138 )
by Björn
02:29
created

lib/patternlibrary/parse-docs.js (5 issues)

1
/**
2
 * Parses for pattern's documentation
3
 * 
4
 * 
5
 * @package Patternlibrary
6
 */
7 1
var async       = require('async');
8 1
var extend      = require('util')._extend;
9 1
var format      = require('string-template');
10 1
var fm          = require('front-matter');
11 1
var fs          = require('fs');
12 1
var glob        = require('glob');
13 1
var globAll     = require('glob-all');
14 1
var path        = require('path');
15 1
var chalk       = require('chalk');
16 1
var extend      = require('extend');
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable extend already seems to be declared on line 8. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
17 1
var sanatizeType = require('../util/sanatize-patterntype');
18
19 1
module.exports = function(file, opts, cb) {
20
    var _this = this; // this => Supercollider ref, this.$PL => Patternlibrary ref
21
    var page = {};
22
    var pageData = fm(file.contents.toString());
23
    var relativePatternPath = path.relative( this.options.partials,  path.dirname(file.path) );
24
    
25 2
    if (typeof(opts) === 'function') {
26
        cb = opts;
27
        opts = {};
0 ignored issues
show
The assignment to variable opts seems to be never used. Consider removing it.
Loading history...
28
    }
29
    // Global attributes
30
    page = pageData.attributes;
31
    //page.__fm = pageData.attributes;
32
    page.docs = '';
33
    page.fileName = path.relative(process.cwd(), file.path);
34
    page._adapterData = {};
35
    page._adapterFiles = {};
36
    page.relatedFiles = [];
37
38
    // Catch Markdown errors
39 2
    if (this.markdown) {
40
        try {
41
            page.docs = this.markdown.render(pageData.body);
42
        }
43
        catch (e) {
44
            throw new Error('Markdown error: ' + e.message);
45
        }
46
    }
47
    else {
48
        page.docs = pageData.body;
49
    }
50
51
    // check for other (mandatory) page.{doctype} 
52 2
    if (!page.source)    { 
53
    	page.source = path.join(relativePatternPath, './index.html');
54
    } else {
55
    	page.source = path.join(relativePatternPath, page.source);
56
    }
57 2
    if (!page.sourcecode) { page.sourcecode = page.source; }
58 2
    if (!page.example)    { page.example    = page.source; }
59 2
    if (!page.specs)      { page.specs      = page.source; }
60 2
    if (!page.changelog)  { page.changelog  = path.join(  relativePatternPath, './changelog.md'); }
61 2
    if (!page.tests)      { page.tests      = path.join(  relativePatternPath, './test.js'); }
62 2
    if (!page.gitinfo)    { page.gitinfo    = path.join(  relativePatternPath, ''); }
63
64
    // Run each adapter's parser, if the page references it
65
    var parseTasks = {};
66
    for (var lib in this.adapters) {
0 ignored issues
show
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
67 2
        if (page[lib]) {
68
        
69
            // Placed inside an IIFE so the value of lib is correct for each function call
70
            (function(lib) {
71
                var collider = {
72
                    "options"  : _this.options,
73
                    "filePath" : path.dirname(page.fileName), //path.relative( _this.$PL.Config.get('partials'),  path.dirname(file.path) ),
74
                    "pattern"  : pageData.title
75
                };
76
          
77
                parseTasks[lib] = function(cb) {
78
                    // Store the original value of the YML property so it can be accessed later if needed
79
                    page._adapterData[lib] = page[lib];
80
  
81
                    // find correct path for 'page[lib]'...
82
                    var adapterFiles = findPath( page[lib], collider );
83
                    page._adapterFiles[lib] = adapterFiles;
84
                    
85
                    // Then find the configuration for the adapter...
86 2
                    var config = extend(_this.adapters[lib].config, _this.options.adapters[lib] || {
87
                        
88
                    });
89
90
                    // ... and run it
91
                    _this.adapters[lib](adapterFiles, config, cb, _this);
92
                };
93
        
94
                parseTasks[lib + '-files'] = function(cb) {
95
                    addFiles(page.relatedFiles, page._adapterFiles[lib], function(files) {
96
                        page.relatedFiles = files;
97
                        cb();
98
                    });
99
                };
100
        
101
            })(lib);
102
      
103
        }
104
    } // for(adapters)
105
106
    async.parallel(parseTasks, function(err, results) {
107
        for (var i in results) {
0 ignored issues
show
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
108
            page[i] = results[i];
109
        }
110
111
        var patternname = sanatizeType(path.dirname(page.source));
112
        _this.data.patterns[patternname] = extend(_this.data.patterns[patternname], page);
113
        //_this.updateDataFile();
114
        _this.log.info('parse tasks finished for "'+chalk.green(patternname)+'"');
115
116
        // debug the main data tree: _this.$PL.debug('tree: ', _this.data);
117
        cb(null, page);
118
    });
119
}
120
121
/**
122
 * find array item-key by object-key value in an array of objects
123
 * 
124
 * @param array
125
 * @param key
126
 * @param value
127
 * @returns integer >= 0 on success, -1 on failure
128
 */
129
function findByKey(array, key, value) {
130
    for (var i in array) {
0 ignored issues
show
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
131 4
        if (array[i][key] && array[i][key] === value) {
132
            return i;
133
        }
134
    }
135
    return -1;
136
}
137
138
/**
139
 * find 'correct' path for '(related)File' globs
140
 * 
141
 * @param   fileGlobs  fileGlobs to look for
142
 * @param   collider   config
143
 * @returns fileGlob
144
 */
145
function findPath(fileGlobs, collider) {
146
    
147
    // look in "partials"/"patterns"' filepath for "file"
148 2
    if ( fs.existsSync( path.join(collider.filePath, fileGlobs) ) ) {
149
        return ( path.join(collider.filePath, fileGlobs) );
150
    }
151
    // look in "partials"/"patterns"' filepath for "*/**/file"
152 2
    if ( fs.existsSync( path.join(collider.filePath, "*/**/", fileGlobs) ) ) {
153
        return ( path.join(collider.filePath, "*/**/", fileGlobs) );
154
    }
155
    
156
    // look in "partials"/"patterns" for "type/name/file" --- (fileGlobs != 'index.html') && 
157 2
    if ( fs.existsSync( path.join(collider.options.partials, fileGlobs) ) ) {
158
        return ( path.join(collider.options.partials, fileGlobs) );
159
    }
160
    
161
    // org. file path
162 2
    if (fs.existsSync( fileGlobs ) ) {
163
        return ( fileGlobs );
164
    }
165
    
166
    // if all fail, return given globs
167
    return(fileGlobs)
168
}
169
170
/**
171
 * add related files to task
172
 * 
173
 * @param   files      related files
174
 * @param   fileGlobs  files to look for
175
 * @param   cb         async callback
176
 */
177
function addFiles(files, fileGlobs, cb) {
178
    var searchGlob = fileGlobs;
179
    globAll(searchGlob, function(err, newFiles) {
180
       cb(files.concat(newFiles));
181
    });
182
}
183