<commit_before>var path = require('path'),
    async = require('async'),
    glob = require('glob'),
    fs = require('fs-extra'),//require('fs'),
    ejs = require('ejs'),
    md = require("github-flavored-markdown"),
    extend = require('util-extend'),
    sanitizer = require('sanitizer'),
    package = require(__dirname + '/package.json');

var VERSION = package.version;

var PATTERNS = {
    comment: /\/\*\s*s?#styleguide([^*]|\*[^/])*\*\//g,
    overview: /\/\*\s*s?#overview([^*]|\*[^/])*\*\//g,
    colors: /\/\*\s*s?#colors([^*]|\*[^/])*\*\//g,
    color: /@(.+)\s{1}(.+)$/,
    splitter: /\n/,
    prefix: /^ *\/?\**(#styleguide|#overview)?\/? */gm,
    line: /^\s*$/gm,
    attr: /^@.+$/gm,
    attrPrefix: /^@/,
    code: /```(.|\s)+```/g,
    codeWrapper: /(```)\n?/g
};
var OPTIONS = {
    overview: __dirname + '/styleguide.md',
    template: __dirname + '/template/index.html',
    includeAssetPath: 'assets/**/*',
    css: './style.css',
    script: null,
    out: './guide',
    title: 'StyleGuide',
    verbose: false,
    clean: false
};

var HELPERS = {
    // currentファイルかどうか
    isCurrent: function(current,file) {
        return (current.file === file.file);
    },
    // 指定した属性が含まれているかどうか
    hasAttribute: function(attributes,attr) {
        return (attributes.indexOf(attr) !== -1);
    }
};

/**
 * FrontNote
 * @param target {string|array} 解析するファイルのminimatch形式文字列またはminimatch形式文字列が入った配列
 * @param option {object} オプション
 * @param callback {callback} 全ての処理が正常に終了したときに実行するコールバック関数
 * @constructor
 */
function FrontNote(target,option,callback) {
    echoLog('Start','FrontNote - ' + VERSION,'green');

    var options = extend({},OPTIONS);
    options = extend(options,option);
    options.out = path.resolve(options.out);

    globArrayConcat(target, function(result) {
        start(null,result);
    });

    function start(err, files) {
        if(err) throw (err);

        var data = [];
        // 外部ファイルを１つずつ読み込み
        async.forEachSeries(files, function(file, callback) {
            fs.readFile(file, 'utf8',function (err, res) {
                if (err) throw(err);
                if (options.verbose) {
                    echoLog('Read',file);
                }

                var overview = res.match(PATTERNS.overview);
                if (overview) {
                    overview = parseComments(overview);
                    if (overview) {
                        overview = overview[0];
                    }
                }

                var colors = res.match(PATTERNS.colors);
                if (colors) {
                    colors = parseColors(colors);
                }

                var comments = res.match(PATTERNS.comment);
                if (comments) {
                    comments = parseComments(comments);
                }
                if(overview || comments || colors) {
                    var fileName = path.basename(file,path.extname(file));
                    var relPath = path.relative(__dirname, path.dirname(file));
                    if (relPath) {
                        relPath = relPath.replace(/\.\.\//g,'').replace(/\//g,'-') + '-';
                    }
                    data.push({
                        file: file,
                        fileName: fileName,
                        url: relPath + fileName + '.html',
                        dirs: file.split(path.sep),
                        ext: path.extname(file),
                        sections: comments,
                        overview: overview,
                        colors: colors
                    });
                }
                callback();
            });
        }, function (err) {
            if (err) throw err;
            createStyleGuide(data,options,callback);
        });
    }
}

/**
 * コメントの塊をパースする
 * @param comments
 * @returns {Array}
 */
function parseComments(comments) {
    var result = [];
    for (var i = 0, len = comments.length; i < len; i++) {
        var com = parseComment(comments[i]);
        if (com) {
            result.push(com);
        }
    }
    return result;
}

/**
 * カラーコメントの塊をパースする
 * @param colors
 * @returns {Array}
 */
function parseColors(colors) {
    var result = [];
    for (var i = 0, len = colors.length; i < len; i++) {
        var color = parseColor(colors[i]);
        if (color) {
            result = result.concat(color);
        }
    }
    return result;
}
/**
 * カラーコメントパースする
 * @param color
 * @returns {Array}
 */
function parseColor(color) {
    var colors = filterPattern(color,PATTERNS.attr,false),
        result = [];
    for(var i = 0,len = colors.length; i < len; i++) {
        var matches = colors[i].match(PATTERNS.color);
        if (matches.length > 2) {
            result.push({
                value: matches[0],
                name: matches[1],
                color: matches[2]
            });
        }
    }
    return result;
}

/**
 * コメントをパースする
 * @param comment
 * @returns {{title: Array, comment: Array, attributes: (*|Array), markdown: *, html: *, code: *}}
 */
function parseComment(comment) {
    comment = comment.replace(PATTERNS.prefix,'');

    // 属性
    var attrs = filterPattern(comment,PATTERNS.attr,false);
    comment = comment.replace(PATTERNS.attr,'');

    // サンプルコード領域
    var code = filterPattern(comment,PATTERNS.code);
    comment = comment.replace(PATTERNS.code,'');

    var result = {
        title: [],
        comment: [],
        attributes: attrs || [],
        code: code
    };

    var lines = comment.split(PATTERNS.splitter),
        hasTitle = false,
        i = 0;

    for (i = 0, len = lines.length; i < len; i++) {
        var line = lines[i];
        if (!hasTitle) {
            if (line) {
                result.title.push(sanitizer.escape(line));
            } else if(result.title.length !== 0) {
                hasTitle = true;
            }
        } else if (line) {
            result.comment.push(sanitizer.escape(line));
        }
    }
    result.title = result.title.join('<br>');
    result.comment = result.comment.join('<br>');

    for (i = 0, len = result.attributes.length; i < len; i++) {
        result.attributes[i] = sanitizer.escape(result.attributes[i].replace(PATTERNS.attrPrefix,''));
    }

    return result;
}

/**
 * 正規表現によって一致した文字列データを返却
 * @param str
 * @param pattern
 * @param trim
 * @returns {*}
 */
function filterPattern(str,pattern,trim) {
    if (trim === false) {
        return str.match(pattern);
    } else {
        var match = str.match(pattern);
        if (match) {
            return match[0].replace(PATTERNS.codeWrapper,'');
        }
        return null;
    }
}

/**
 * スタイルガイド作成
 * @param data
 * @param options
 */
function createStyleGuide(data,options,callback) {
    async.waterfall([
        //出力先削除
        function(callback) {
            if (options.clean) {
                fs.remove(options.out,callback);
            } else {
                callback();
            }
        },
        //テンプレート読み込み
        function(callback) {
            //テンプレートファイルの読み込み
            fs.readFile(options.template, 'utf8',function (err, res) {
                if (err) throw(err);
                if (options.verbose) {
                    echoLog('Read',options.template);
                }
                callback(null,res);
            });
        },
        //overviewファイルを読み込んでindexを作成
        function(template,callback) {
            //styleguide.mdを読み込み
            fs.readFile(options.overview, 'utf8',function (err, res) {
                if (err) throw(err);
                if (options.verbose) {
                    echoLog('Read',options.overview);
                }
                //EJSを使ってテンプレートレンダリング
                var rendered = ejs.render(template, {
                    title: options.title,
                    current: md.parse(res),
                    files: data,
                    overview: true,
                    helpers: HELPERS,
                    css: generateIncludeCss(options.css),
                    script: generateIncludeScript(options.script)
                });
                // ディレクトリを作りつつファイル出力
                fs.outputFile(options.out + '/index.html', rendered, function (err) {
                    if (err) throw err;
                    if (options.verbose) {
                        echoLog('Write',options.out + '/index.html');
                    }
                    callback(null,template);
                });
            });
        },
        //ファイルごとにスタイルガイドを作成
        function(template,callback) {
            async.eachSeries(data,function(section,next) {
                //EJSを使ってテンプレートレンダリング
                var rend = ejs.render(template, {
                    title: options.title,
                    current: section,
                    files: data,
                    overview: false,
                    helpers: HELPERS,
                    css: generateIncludeCss(options.css),
                    script: generateIncludeScript(options.script)
                });
                if (options.verbose) {
                    echoLog('Render',section.file);
                }
                //スタイルガイド出力
                fs.outputFile(options.out + '/' + section.url, rend, function (err) {
                    if (err) throw err;
                    if (options.verbose) {
                        echoLog('Write',options.out + '/' + section.fileName + '.html');
                    }
                    next();
                });
            },function() {
                callback();
            });
        },
        //スタイルガイドができたらincludeするその他ファイルをコピー
        function(callback) {
            if (options.includeAssetPath) {
                // includeAssetPathが文字列ならそのまま実行、配列ならeachで回して実行
                if (typeof options.includeAssetPath === 'string') {
                    readFiles(options.includeAssetPath,callback);
                } else {
                    async.each(options.includeAssetPath,function(targetPath,next) {
                        readFiles(targetPath,next);
                    },function() {
                        callback();
                    });
                }
            } else {
                callback();
            }
            /**
             * ファイルを１つずつ読み込んでコピー
             * @param pathPattern
             * @param callback
             */
            function readFiles(pathPattern,callback) {
                async.waterfall([
                    //パターン文字列からファイルパス配列取得
                    function(next) {
                        //テンプレートディレクトリからの相対でminimatch形式の文字列を作成
                        pathPattern = path.dirname(options.template) + '/' + pathPattern;
                        //対象ファイル一覧取得
                        glob(pathPattern, function(err,files) {
                            if (err) throw(err);
                            next(null,files);
                        });
                    },
                    //ファイルパス配列をもとにファイルを出力ディレクトリに複製
                    function(files,next) {
                        copyFiles(files,options,next)
                    },
                    function() {
                        callback();
                    }
                ]);
            }
        },
        //完了
        function() {
            echoLog('Finish','FrontNote - (c)copyright frontainer.com All rights reserved.','green');
            if (callback) {
                callback();
            }
        }
    ]);
}

/**
 * ファイルをコピー
 * @param files
 * @param options
 * @param callback
 */
function copyFiles(files,options,callback) {
    async.each(files,function(file,next) {
        // ファイル情報取得
        fs.stat(file, function(err,stats) {
            if(err) throw(err);
            //ファイル以外（ディレクトリ）だったら無視して次へ
            if (!stats.isFile()) {
                next();
            } else {
                // テンプレートディレクトリからの相対パスでincludeファイルを参照
                var relPath = path.relative(path.dirname(options.template),file);
                //コピー開始
                fs.copy(file, options.out + '/' + relPath, function(err){
                    if (err) throw(err);
                    if (options.verbose) {
                        echoLog('Copy',file + ' => ' + options.out + '/' + relPath);
                    }
                    next();
                });
            }
        });
    },function() {
        callback();
    });
}

/**
 * console.logを色付きで出力
 * @param label
 * @param text
 * @param color
 */
function echoLog(label,text,color) {
    var defaultColor = '\u001b[30m'; //black
    var colorCode = defaultColor;
    switch(color) {
        case 'red':
            colorCode = '\u001b[31m';
            break;
        case 'green':
            colorCode = '\u001b[32m';
            break;
        case 'yellow':
            colorCode = '\u001b[33m';
            break;
        default:
            break;
    }
    console.log(colorCode + '[' + label + '] ' + defaultColor + text);
}

/**
 * HTMLに追加読み込みするCSSファイルパスまたはパスが入った配列からタグを生成
 * @param arr
 * @return {string|array}
 */
function generateIncludeCss(arr) {
    if (!arr) return '';
    if (typeof arr === 'string') {
        return '<link rel="stylesheet" href="'+arr+'"/>';
    }
    var result = [];
    for (var i = 0,len = arr.length; i < len; i++) {
        result.push('<link rel="stylesheet" href="'+arr[i]+'"/>');
    }
    return result.join('\n');
}
/**
 * HTMLに追加読み込みするJSファイルパスまたはパスが入った配列からタグを生成
 * @param arr {string|array}
 */
function generateIncludeScript(arr) {
    if (!arr) return '';
    if (typeof arr === 'string') {
        return '<script src="'+arr+'"></script>';
    }
    var result = [];
    for (var i = 0,len = arr.length; i < len; i++) {
        result.push('<script src="'+arr[i]+'"></script>');
    }
    return result.join('\n');
}

/**
 * globパターン文字列または配列からファイルパスの配列を生成
 * @param arr{string|array}
 * @param callback
 */
function globArrayConcat(arr,callback) {
    var result = [];
    if (arr instanceof Array === false) {
        arr = [arr];
    }
    async.each(arr, function(pattern,next) {
        glob(pattern, function(err,files) {
            if (err) throw err;
            result = result.concat(files);
            next();
        });
    }, function() {
        callback(result);
    });
}

// プラグイン関数をエクスポート
module.exports = FrontNote;<commit_msg>winでパスが不正で出力が正しく行われない不具合を修正<commit_after>var path = require('path'),
    async = require('async'),
    glob = require('glob'),
    fs = require('fs-extra'),//require('fs'),
    ejs = require('ejs'),
    md = require("github-flavored-markdown"),
    extend = require('util-extend'),
    sanitizer = require('sanitizer'),
    package = require(__dirname + '/package.json');

var VERSION = package.version;

var PATTERNS = {
    comment: /\/\*\s*s?#styleguide([^*]|\*[^/])*\*\//g,
    overview: /\/\*\s*s?#overview([^*]|\*[^/])*\*\//g,
    colors: /\/\*\s*s?#colors([^*]|\*[^/])*\*\//g,
    color: /@(.+)\s{1}(.+)$/,
    splitter: /\n/,
    prefix: /^ *\/?\**(#styleguide|#overview)?\/? */gm,
    line: /^\s*$/gm,
    attr: /^@.+$/gm,
    attrPrefix: /^@/,
    code: /```(.|\s)+```/g,
    codeWrapper: /(```)\n?/g
};
var OPTIONS = {
    overview: __dirname + '/styleguide.md',
    template: __dirname + '/template/index.html',
    includeAssetPath: 'assets/**/*',
    css: './style.css',
    script: null,
    out: './guide',
    title: 'StyleGuide',
    verbose: false,
    clean: false
};

var HELPERS = {
    // currentファイルかどうか
    isCurrent: function(current,file) {
        return (current.file === file.file);
    },
    // 指定した属性が含まれているかどうか
    hasAttribute: function(attributes,attr) {
        return (attributes.indexOf(attr) !== -1);
    }
};

/**
 * FrontNote
 * @param target {string|array} 解析するファイルのminimatch形式文字列またはminimatch形式文字列が入った配列
 * @param option {object} オプション
 * @param callback {callback} 全ての処理が正常に終了したときに実行するコールバック関数
 * @constructor
 */
function FrontNote(target,option,callback) {
    echoLog('Start','FrontNote - ' + VERSION,'green');

    var options = extend({},OPTIONS);
    options = extend(options,option);
    options.out = path.resolve(options.out);

    globArrayConcat(target, function(result) {
        start(null,result);
    });

    function start(err, files) {
        if(err) throw (err);

        var data = [];
        // 外部ファイルを１つずつ読み込み
        async.forEachSeries(files, function(file, callback) {
            fs.readFile(file, 'utf8',function (err, res) {
                if (err) throw(err);
                if (options.verbose) {
                    echoLog('Read',file);
                }

                var overview = res.match(PATTERNS.overview);
                if (overview) {
                    overview = parseComments(overview);
                    if (overview) {
                        overview = overview[0];
                    }
                }

                var colors = res.match(PATTERNS.colors);
                if (colors) {
                    colors = parseColors(colors);
                }

                var comments = res.match(PATTERNS.comment);
                if (comments) {
                    comments = parseComments(comments);
                }
                if(overview || comments || colors) {
                    var fileName = path.basename(file,path.extname(file));
                    var relPath = path.relative(__dirname, path.dirname(file));
                    if (relPath) {
                        relPath = relPath.replace(/\.\.\//g,'').replace(/\.\.\\/g,'').replace(/\//g,'-').replace(/\\/g,'-') + '-';
                    }
                    data.push({
                        file: file,
                        fileName: fileName,
                        url: relPath + fileName + '.html',
                        dirs: file.split(path.sep),
                        ext: path.extname(file),
                        sections: comments,
                        overview: overview,
                        colors: colors
                    });
                }
                callback();
            });
        }, function (err) {
            if (err) throw err;
            createStyleGuide(data,options,callback);
        });
    }
}

/**
 * コメントの塊をパースする
 * @param comments
 * @returns {Array}
 */
function parseComments(comments) {
    var result = [];
    for (var i = 0, len = comments.length; i < len; i++) {
        var com = parseComment(comments[i]);
        if (com) {
            result.push(com);
        }
    }
    return result;
}

/**
 * カラーコメントの塊をパースする
 * @param colors
 * @returns {Array}
 */
function parseColors(colors) {
    var result = [];
    for (var i = 0, len = colors.length; i < len; i++) {
        var color = parseColor(colors[i]);
        if (color) {
            result = result.concat(color);
        }
    }
    return result;
}
/**
 * カラーコメントパースする
 * @param color
 * @returns {Array}
 */
function parseColor(color) {
    var colors = filterPattern(color,PATTERNS.attr,false),
        result = [];
    for(var i = 0,len = colors.length; i < len; i++) {
        var matches = colors[i].match(PATTERNS.color);
        if (matches.length > 2) {
            result.push({
                value: matches[0],
                name: matches[1],
                color: matches[2]
            });
        }
    }
    return result;
}

/**
 * コメントをパースする
 * @param comment
 * @returns {{title: Array, comment: Array, attributes: (*|Array), markdown: *, html: *, code: *}}
 */
function parseComment(comment) {
    comment = comment.replace(PATTERNS.prefix,'');

    // 属性
    var attrs = filterPattern(comment,PATTERNS.attr,false);
    comment = comment.replace(PATTERNS.attr,'');

    // サンプルコード領域
    var code = filterPattern(comment,PATTERNS.code);
    comment = comment.replace(PATTERNS.code,'');

    var result = {
        title: [],
        comment: [],
        attributes: attrs || [],
        code: code
    };

    var lines = comment.split(PATTERNS.splitter),
        hasTitle = false,
        i = 0;

    for (i = 0, len = lines.length; i < len; i++) {
        var line = lines[i];
        if (!hasTitle) {
            if (line) {
                result.title.push(sanitizer.escape(line));
            } else if(result.title.length !== 0) {
                hasTitle = true;
            }
        } else if (line) {
            result.comment.push(sanitizer.escape(line));
        }
    }
    result.title = result.title.join('<br>');
    result.comment = result.comment.join('<br>');

    for (i = 0, len = result.attributes.length; i < len; i++) {
        result.attributes[i] = sanitizer.escape(result.attributes[i].replace(PATTERNS.attrPrefix,''));
    }

    return result;
}

/**
 * 正規表現によって一致した文字列データを返却
 * @param str
 * @param pattern
 * @param trim
 * @returns {*}
 */
function filterPattern(str,pattern,trim) {
    if (trim === false) {
        return str.match(pattern);
    } else {
        var match = str.match(pattern);
        if (match) {
            return match[0].replace(PATTERNS.codeWrapper,'');
        }
        return null;
    }
}

/**
 * スタイルガイド作成
 * @param data
 * @param options
 */
function createStyleGuide(data,options,callback) {
    async.waterfall([
        //出力先削除
        function(callback) {
            if (options.clean) {
                fs.remove(options.out,callback);
            } else {
                callback();
            }
        },
        //テンプレート読み込み
        function(callback) {
            //テンプレートファイルの読み込み
            fs.readFile(options.template, 'utf8',function (err, res) {
                if (err) throw(err);
                if (options.verbose) {
                    echoLog('Read',options.template);
                }
                callback(null,res);
            });
        },
        //overviewファイルを読み込んでindexを作成
        function(template,callback) {
            //styleguide.mdを読み込み
            fs.readFile(options.overview, 'utf8',function (err, res) {
                if (err) throw(err);
                if (options.verbose) {
                    echoLog('Read',options.overview);
                }
                //EJSを使ってテンプレートレンダリング
                var rendered = ejs.render(template, {
                    title: options.title,
                    current: md.parse(res),
                    files: data,
                    overview: true,
                    helpers: HELPERS,
                    css: generateIncludeCss(options.css),
                    script: generateIncludeScript(options.script)
                });
                // ディレクトリを作りつつファイル出力
                fs.outputFile(options.out + '/index.html', rendered, function (err) {
                    if (err) throw err;
                    if (options.verbose) {
                        echoLog('Write',options.out + '/index.html');
                    }
                    callback(null,template);
                });
            });
        },
        //ファイルごとにスタイルガイドを作成
        function(template,callback) {
            async.eachSeries(data,function(section,next) {
                //EJSを使ってテンプレートレンダリング
                var rend = ejs.render(template, {
                    title: options.title,
                    current: section,
                    files: data,
                    overview: false,
                    helpers: HELPERS,
                    css: generateIncludeCss(options.css),
                    script: generateIncludeScript(options.script)
                });
                if (options.verbose) {
                    echoLog('Render',section.file);
                }
                //スタイルガイド出力
                fs.outputFile(options.out + '/' + section.url, rend, function (err) {
                    if (err) throw err;
                    if (options.verbose) {
                        echoLog('Write',options.out + '/' + section.fileName + '.html');
                    }
                    next();
                });
            },function() {
                callback();
            });
        },
        //スタイルガイドができたらincludeするその他ファイルをコピー
        function(callback) {
            if (options.includeAssetPath) {
                // includeAssetPathが文字列ならそのまま実行、配列ならeachで回して実行
                if (typeof options.includeAssetPath === 'string') {
                    readFiles(options.includeAssetPath,callback);
                } else {
                    async.each(options.includeAssetPath,function(targetPath,next) {
                        readFiles(targetPath,next);
                    },function() {
                        callback();
                    });
                }
            } else {
                callback();
            }
            /**
             * ファイルを１つずつ読み込んでコピー
             * @param pathPattern
             * @param callback
             */
            function readFiles(pathPattern,callback) {
                async.waterfall([
                    //パターン文字列からファイルパス配列取得
                    function(next) {
                        //テンプレートディレクトリからの相対でminimatch形式の文字列を作成
                        pathPattern = path.dirname(options.template) + '/' + pathPattern;
                        //対象ファイル一覧取得
                        glob(pathPattern, function(err,files) {
                            if (err) throw(err);
                            next(null,files);
                        });
                    },
                    //ファイルパス配列をもとにファイルを出力ディレクトリに複製
                    function(files,next) {
                        copyFiles(files,options,next)
                    },
                    function() {
                        callback();
                    }
                ]);
            }
        },
        //完了
        function() {
            echoLog('Finish','FrontNote - (c)copyright frontainer.com All rights reserved.','green');
            if (callback) {
                callback();
            }
        }
    ]);
}

/**
 * ファイルをコピー
 * @param files
 * @param options
 * @param callback
 */
function copyFiles(files,options,callback) {
    async.each(files,function(file,next) {
        // ファイル情報取得
        fs.stat(file, function(err,stats) {
            if(err) throw(err);
            //ファイル以外（ディレクトリ）だったら無視して次へ
            if (!stats.isFile()) {
                next();
            } else {
                // テンプレートディレクトリからの相対パスでincludeファイルを参照
                var relPath = path.relative(path.dirname(options.template),file);
                //コピー開始
                fs.copy(file, options.out + '/' + relPath, function(err){
                    if (err) throw(err);
                    if (options.verbose) {
                        echoLog('Copy',file + ' => ' + options.out + '/' + relPath);
                    }
                    next();
                });
            }
        });
    },function() {
        callback();
    });
}

/**
 * console.logを色付きで出力
 * @param label
 * @param text
 * @param color
 */
function echoLog(label,text,color) {
    var defaultColor = '\u001b[30m'; //black
    var colorCode = defaultColor;
    switch(color) {
        case 'red':
            colorCode = '\u001b[31m';
            break;
        case 'green':
            colorCode = '\u001b[32m';
            break;
        case 'yellow':
            colorCode = '\u001b[33m';
            break;
        default:
            break;
    }
    console.log(colorCode + '[' + label + '] ' + defaultColor + text);
}

/**
 * HTMLに追加読み込みするCSSファイルパスまたはパスが入った配列からタグを生成
 * @param arr
 * @return {string|array}
 */
function generateIncludeCss(arr) {
    if (!arr) return '';
    if (typeof arr === 'string') {
        return '<link rel="stylesheet" href="'+arr+'"/>';
    }
    var result = [];
    for (var i = 0,len = arr.length; i < len; i++) {
        result.push('<link rel="stylesheet" href="'+arr[i]+'"/>');
    }
    return result.join('\n');
}
/**
 * HTMLに追加読み込みするJSファイルパスまたはパスが入った配列からタグを生成
 * @param arr {string|array}
 */
function generateIncludeScript(arr) {
    if (!arr) return '';
    if (typeof arr === 'string') {
        return '<script src="'+arr+'"></script>';
    }
    var result = [];
    for (var i = 0,len = arr.length; i < len; i++) {
        result.push('<script src="'+arr[i]+'"></script>');
    }
    return result.join('\n');
}

/**
 * globパターン文字列または配列からファイルパスの配列を生成
 * @param arr{string|array}
 * @param callback
 */
function globArrayConcat(arr,callback) {
    var result = [];
    if (arr instanceof Array === false) {
        arr = [arr];
    }
    async.each(arr, function(pattern,next) {
        glob(pattern, function(err,files) {
            if (err) throw err;
            result = result.concat(files);
            next();
        });
    }, function() {
        callback(result);
    });
}

// プラグイン関数をエクスポート
module.exports = FrontNote;<|endoftext|>


<commit_before>'use strict'

var visit = require('unist-util-visit')
var normalize = require('nlcst-normalize')
var isLiteral = require('nlcst-is-literal')

var own = {}.hasOwnProperty

module.exports = search

var C_SPACE = ' '
var T_WORD = 'WordNode'
var T_WHITE_SPACE = 'WhiteSpaceNode'

function search(tree, phrases, handler, options) {
  var settings = options || {}
  var apos = settings.allowApostrophes || options
  var dashes = settings.allowDashes || false
  var literals = settings.allowLiterals
  var config = {allowApostrophes: apos, allowDashes: dashes}
  var byWord = {'*': []}
  var length
  var index
  var key

  if (!tree || !tree.type) {
    throw new Error('Expected node')
  }

  if (typeof phrases !== 'object') {
    throw new Error('Expected object for phrases')
  }

  length = phrases.length
  index = -1

  if ('length' in phrases) {
    while (++index < length) {
      handlePhrase(phrases[index])
    }
  } else {
    for (key in phrases) {
      handlePhrase(key)
    }
  }

  /* Search the tree. */
  visit(tree, T_WORD, visitor)

  /* Test a phrase.   */
  function test(phrase, position, parent) {
    var siblings = parent.children
    var node = siblings[position]
    var count = siblings.length
    var queue = [node]
    var expressions = phrase.split(C_SPACE).slice(1)
    var length = expressions.length
    var index = -1
    var expression

    /* Move one position forward. */
    position++

    /* Iterate over `expressions`. */
    while (++index < length) {
      /* Allow joining white-space. */
      while (position < count) {
        node = siblings[position]

        if (node.type !== T_WHITE_SPACE) {
          break
        }

        queue.push(node)
        position++
      }

      node = siblings[position]
      expression = expressions[index]

      /* Exit if there are no nodes left, if the
       * current node is not a word, or if the
       * current word does not match the search for
       * value. */
      if (
        !node ||
        node.type !== T_WORD ||
        (expression !== '*' &&
          normalize(expression, config) !== normalize(node, config))
      ) {
        return
      }

      queue.push(node)
      position++
    }

    return queue
  }

  /* Visitor for `WordNode`s.   */
  function visitor(node, position, parent) {
    var word
    var phrases
    var length
    var index
    var result

    if (!literals && isLiteral(parent, position)) {
      return
    }

    word = normalize(node, config)
    phrases = byWord['*'].concat(own.call(byWord, word) ? byWord[word] : [])
    length = phrases.length
    index = -1

    while (++index < length) {
      result = test(phrases[index], position, parent)

      if (result) {
        handler(result, position, parent, phrases[index])
      }
    }
  }

  /* Handle a phrase. */
  function handlePhrase(phrase) {
    var firstWord = normalize(phrase.split(C_SPACE, 1)[0], config)

    if (own.call(byWord, firstWord)) {
      byWord[firstWord].push(phrase)
    } else {
      byWord[firstWord] = [phrase]
    }
  }
}
<commit_msg>Refactor comment-style<commit_after>'use strict'

var visit = require('unist-util-visit')
var normalize = require('nlcst-normalize')
var isLiteral = require('nlcst-is-literal')

var own = {}.hasOwnProperty

module.exports = search

var C_SPACE = ' '
var T_WORD = 'WordNode'
var T_WHITE_SPACE = 'WhiteSpaceNode'

function search(tree, phrases, handler, options) {
  var settings = options || {}
  var apos = settings.allowApostrophes || options
  var dashes = settings.allowDashes || false
  var literals = settings.allowLiterals
  var config = {allowApostrophes: apos, allowDashes: dashes}
  var byWord = {'*': []}
  var length
  var index
  var key

  if (!tree || !tree.type) {
    throw new Error('Expected node')
  }

  if (typeof phrases !== 'object') {
    throw new Error('Expected object for phrases')
  }

  length = phrases.length
  index = -1

  if ('length' in phrases) {
    while (++index < length) {
      handlePhrase(phrases[index])
    }
  } else {
    for (key in phrases) {
      handlePhrase(key)
    }
  }

  // Search the tree.
  visit(tree, T_WORD, visitor)

  // Test a phrase.
  function test(phrase, position, parent) {
    var siblings = parent.children
    var node = siblings[position]
    var count = siblings.length
    var queue = [node]
    var expressions = phrase.split(C_SPACE).slice(1)
    var length = expressions.length
    var index = -1
    var expression

    // Move one position forward.
    position++

    // Iterate over `expressions`.
    while (++index < length) {
      // Allow joining white-space.
      while (position < count) {
        node = siblings[position]

        if (node.type !== T_WHITE_SPACE) {
          break
        }

        queue.push(node)
        position++
      }

      node = siblings[position]
      expression = expressions[index]

      // Exit if there are no nodes left, if the current node is not a word, or
      // if the current word does not match the search for value.
      if (
        !node ||
        node.type !== T_WORD ||
        (expression !== '*' &&
          normalize(expression, config) !== normalize(node, config))
      ) {
        return
      }

      queue.push(node)
      position++
    }

    return queue
  }

  // Visitor for `WordNode`s.
  function visitor(node, position, parent) {
    var word
    var phrases
    var length
    var index
    var result

    if (!literals && isLiteral(parent, position)) {
      return
    }

    word = normalize(node, config)
    phrases = byWord['*'].concat(own.call(byWord, word) ? byWord[word] : [])
    length = phrases.length
    index = -1

    while (++index < length) {
      result = test(phrases[index], position, parent)

      if (result) {
        handler(result, position, parent, phrases[index])
      }
    }
  }

  // Handle a phrase.
  function handlePhrase(phrase) {
    var firstWord = normalize(phrase.split(C_SPACE, 1)[0], config)

    if (own.call(byWord, firstWord)) {
      byWord[firstWord].push(phrase)
    } else {
      byWord[firstWord] = [phrase]
    }
  }
}
<|endoftext|>


<commit_before>/**
 * Module dependencies
 */

var Onus = require('onus');
var React = require('react');

var componentCache = {};

module.exports = function(conf) {
  var render = conf.render;
  return Onus({
    render: function(DOM, $get, props, state, _yield, params, query, forms, t) {
      var contents = render(format, $get, props, state, _yield, params, query, forms, t);
      return DOM('style', null, '\n' + Array.isArray(contents) ? contents.join('') : contents);
    }
  });
}

function format(selectors, props) {
  return selectors.join('\n') + ' {\n' + formatProps(props) + '\n}\n';
}

function formatProps(props) {
  var parts = [];
  for (var k in props) {
    if (k === 'key') continue;
    parts.push('  ' + k + ':' + props[k] + ';');
  }
  return parts.join('\n');
}
<commit_msg>move join to its own line<commit_after>/**
 * Module dependencies
 */

var Onus = require('onus');
var React = require('react');

var componentCache = {};

module.exports = function(conf) {
  var render = conf.render;
  return Onus({
    render: function(DOM, $get, props, state, _yield, params, query, forms, t) {
      var out = render(format, $get, props, state, _yield, params, query, forms, t);
      var style = Array.isArray(out) ? out.join('') : out;
      return DOM('style', null, '\n' + style);
    }
  });
}

function format(selectors, props) {
  return selectors.join('\n') + ' {\n' + formatProps(props) + '\n}\n';
}

function formatProps(props) {
  var parts = [];
  for (var k in props) {
    if (k === 'key') continue;
    parts.push('  ' + k + ':' + props[k] + ';');
  }
  return parts.join('\n');
}
<|endoftext|>


<commit_before>'use strict'

module.exports = [
  '0.0.1'
, '0.0.2'
, '0.0.3'
, '0.0.4'
, '0.0.5'
, '0.0.6'
, '0.1.0'
, '0.1.1'
, '0.1.2'
, '0.1.3'
, '0.1.4'
, '0.1.5'
, '0.1.6'
, '0.1.7'
, '0.1.8'
, '0.1.9'
, '0.1.10'
, '0.1.11'
, '0.1.12'
, '0.1.13'
, '0.1.14'
, '0.1.15'
, '0.1.16'
, '0.1.17'
, '0.1.18'
, '0.1.19'
, '0.1.20'
, '0.1.21'
, '0.1.22'
, '0.1.23'
, '0.1.24'
, '0.1.25'
, '0.1.26'
, '0.1.27'
, '0.1.28'
, '0.1.29'
, '0.1.30'
, '0.1.31'
, '0.1.32'
, '0.1.33'
, '0.1.90'
, '0.1.91'
, '0.1.92'
, '0.1.93'
, '0.1.94'
, '0.1.95'
, '0.1.96'
, '0.1.97'
, '0.1.98'
, '0.1.99'
, '0.1.100'
, '0.1.101'
, '0.1.102'
, '0.1.103'
, '0.1.104'
, '0.2.0'
, '0.2.1'
, '0.2.2'
, '0.2.3'
, '0.2.4'
, '0.2.5'
, '0.2.6'
, '0.3.0'
, '0.3.1'
, '0.3.2'
, '0.3.3'
, '0.3.4'
, '0.3.5'
, '0.3.6'
, '0.3.7'
, '0.3.8'
, '0.4.0'
, '0.4.1'
, '0.4.2'
, '0.4.3'
, '0.4.4'
, '0.4.5'
, '0.4.6'
, '0.4.7'
, '0.4.8'
, '0.4.9'
, '0.4.10'
, '0.4.11'
, '0.4.12'
, '0.5.0'
, '0.5.1'
, '0.5.2'
, '0.5.3'
, '0.5.4'
, '0.5.5'
, '0.5.6'
, '0.5.7'
, '0.5.8'
, '0.5.9'
, '0.5.10'
, '0.6.0'
, '0.6.1'
, '0.6.2'
, '0.6.3'
, '0.6.4'
, '0.6.5'
, '0.6.6'
, '0.6.7'
, '0.6.8'
, '0.6.9'
, '0.6.10'
, '0.6.11'
, '0.6.12'
, '0.6.13'
, '0.6.14'
, '0.6.15'
, '0.6.16'
, '0.6.17'
, '0.6.18'
, '0.6.19'
, '0.6.20'
, '0.6.21'
, '0.7.0'
, '0.7.1'
, '0.7.2'
, '0.7.3'
, '0.7.4'
, '0.7.5'
, '0.7.6'
, '0.7.7'
, '0.7.8'
, '0.7.9'
, '0.7.10'
, '0.7.11'
, '0.7.12'
, '0.8.0'
, '0.8.1'
, '0.8.2'
, '0.8.3'
, '0.8.4'
, '0.8.5'
, '0.8.6'
, '0.8.7'
, '0.8.8'
, '0.8.9'
, '0.8.10'
, '0.8.11'
, '0.8.12'
, '0.8.13'
, '0.8.14'
, '0.8.15'
, '0.8.16'
, '0.8.17'
, '0.8.18'
, '0.8.19'
, '0.8.20'
, '0.8.21'
, '0.8.22'
, '0.8.23'
, '0.8.24'
, '0.8.25'
, '0.8.26'
, '0.8.27'
, '0.8.28'
, '0.9.0'
, '0.9.1'
, '0.9.2'
, '0.9.3'
, '0.9.4'
, '0.9.5'
, '0.9.6'
, '0.9.7'
, '0.9.8'
, '0.9.9'
, '0.9.10'
, '0.9.11'
, '0.9.12'
, '0.10.0'
, '0.10.1'
, '0.10.2'
, '0.10.3'
, '0.10.4'
, '0.10.5'
, '0.10.6'
, '0.10.7'
, '0.10.8'
, '0.10.9'
, '0.10.10'
, '0.10.11'
, '0.10.12'
, '0.10.13'
, '0.10.14'
, '0.10.15'
, '0.10.16'
, '0.10.17'
, '0.10.18'
, '0.10.19'
, '0.10.20'
, '0.10.21'
, '0.10.22'
, '0.10.23'
, '0.10.24'
, '0.10.25'
, '0.10.26'
, '0.10.27'
, '0.10.28'
, '0.10.29'
, '0.10.30'
, '0.10.31'
, '0.10.32'
, '0.10.33'
, '0.10.34'
, '0.10.35'
, '0.10.36'
, '0.10.37'
, '0.10.38'
, '0.10.39'
, '0.10.40'
, '0.11.0'
, '0.11.1'
, '0.11.2'
, '0.11.3'
, '0.11.4'
, '0.11.5'
, '0.11.6'
, '0.11.7'
, '0.11.8'
, '0.11.9'
, '0.11.10'
, '0.11.11'
, '0.11.12'
, '0.11.13'
, '0.11.14'
, '0.11.15'
, '0.11.16'
, '0.12.0'
, '0.12.1'
, '0.12.2'
, '0.12.3'
, '0.12.4'
, '0.12.5'
, '0.12.6'
, '0.12.7'
, '1.0.0'
, '1.0.1'
, '1.0.2'
, '1.0.3'
, '1.0.4'
, '1.1.0'
, '1.2.0'
, '1.3.0'
, '1.4.1'
, '1.4.2'
, '1.4.3'
, '1.5.0'
, '1.5.1'
, '1.6.0'
, '1.6.1'
, '1.6.2'
, '1.6.3'
, '1.6.4'
, '1.7.0'
, '1.7.1'
, '1.8.1'
, '1.8.2'
, '1.8.3'
, '1.8.4'
, '2.0.0'
, '2.0.1'
, '2.0.2'
, '2.1.0'
, '2.2.0'
, '2.2.1'
, '2.3.0'
, '2.3.1'
, '2.3.2'
, '2.3.3'
, '2.3.4'
, '2.4.0'
, '2.5.0'
, '3.0.0'
, '3.1.0'
, '3.2.0'
, '3.3.0'
, '3.3.1'
, '4.0.0'
, '4.1.0'
, '4.1.1'
, '4.1.2'
, '4.2.0'
, '4.2.1'
, '5.0.0'
]
<commit_msg>add v4.2.2<commit_after>'use strict'

module.exports = [
  '0.0.1'
, '0.0.2'
, '0.0.3'
, '0.0.4'
, '0.0.5'
, '0.0.6'
, '0.1.0'
, '0.1.1'
, '0.1.2'
, '0.1.3'
, '0.1.4'
, '0.1.5'
, '0.1.6'
, '0.1.7'
, '0.1.8'
, '0.1.9'
, '0.1.10'
, '0.1.11'
, '0.1.12'
, '0.1.13'
, '0.1.14'
, '0.1.15'
, '0.1.16'
, '0.1.17'
, '0.1.18'
, '0.1.19'
, '0.1.20'
, '0.1.21'
, '0.1.22'
, '0.1.23'
, '0.1.24'
, '0.1.25'
, '0.1.26'
, '0.1.27'
, '0.1.28'
, '0.1.29'
, '0.1.30'
, '0.1.31'
, '0.1.32'
, '0.1.33'
, '0.1.90'
, '0.1.91'
, '0.1.92'
, '0.1.93'
, '0.1.94'
, '0.1.95'
, '0.1.96'
, '0.1.97'
, '0.1.98'
, '0.1.99'
, '0.1.100'
, '0.1.101'
, '0.1.102'
, '0.1.103'
, '0.1.104'
, '0.2.0'
, '0.2.1'
, '0.2.2'
, '0.2.3'
, '0.2.4'
, '0.2.5'
, '0.2.6'
, '0.3.0'
, '0.3.1'
, '0.3.2'
, '0.3.3'
, '0.3.4'
, '0.3.5'
, '0.3.6'
, '0.3.7'
, '0.3.8'
, '0.4.0'
, '0.4.1'
, '0.4.2'
, '0.4.3'
, '0.4.4'
, '0.4.5'
, '0.4.6'
, '0.4.7'
, '0.4.8'
, '0.4.9'
, '0.4.10'
, '0.4.11'
, '0.4.12'
, '0.5.0'
, '0.5.1'
, '0.5.2'
, '0.5.3'
, '0.5.4'
, '0.5.5'
, '0.5.6'
, '0.5.7'
, '0.5.8'
, '0.5.9'
, '0.5.10'
, '0.6.0'
, '0.6.1'
, '0.6.2'
, '0.6.3'
, '0.6.4'
, '0.6.5'
, '0.6.6'
, '0.6.7'
, '0.6.8'
, '0.6.9'
, '0.6.10'
, '0.6.11'
, '0.6.12'
, '0.6.13'
, '0.6.14'
, '0.6.15'
, '0.6.16'
, '0.6.17'
, '0.6.18'
, '0.6.19'
, '0.6.20'
, '0.6.21'
, '0.7.0'
, '0.7.1'
, '0.7.2'
, '0.7.3'
, '0.7.4'
, '0.7.5'
, '0.7.6'
, '0.7.7'
, '0.7.8'
, '0.7.9'
, '0.7.10'
, '0.7.11'
, '0.7.12'
, '0.8.0'
, '0.8.1'
, '0.8.2'
, '0.8.3'
, '0.8.4'
, '0.8.5'
, '0.8.6'
, '0.8.7'
, '0.8.8'
, '0.8.9'
, '0.8.10'
, '0.8.11'
, '0.8.12'
, '0.8.13'
, '0.8.14'
, '0.8.15'
, '0.8.16'
, '0.8.17'
, '0.8.18'
, '0.8.19'
, '0.8.20'
, '0.8.21'
, '0.8.22'
, '0.8.23'
, '0.8.24'
, '0.8.25'
, '0.8.26'
, '0.8.27'
, '0.8.28'
, '0.9.0'
, '0.9.1'
, '0.9.2'
, '0.9.3'
, '0.9.4'
, '0.9.5'
, '0.9.6'
, '0.9.7'
, '0.9.8'
, '0.9.9'
, '0.9.10'
, '0.9.11'
, '0.9.12'
, '0.10.0'
, '0.10.1'
, '0.10.2'
, '0.10.3'
, '0.10.4'
, '0.10.5'
, '0.10.6'
, '0.10.7'
, '0.10.8'
, '0.10.9'
, '0.10.10'
, '0.10.11'
, '0.10.12'
, '0.10.13'
, '0.10.14'
, '0.10.15'
, '0.10.16'
, '0.10.17'
, '0.10.18'
, '0.10.19'
, '0.10.20'
, '0.10.21'
, '0.10.22'
, '0.10.23'
, '0.10.24'
, '0.10.25'
, '0.10.26'
, '0.10.27'
, '0.10.28'
, '0.10.29'
, '0.10.30'
, '0.10.31'
, '0.10.32'
, '0.10.33'
, '0.10.34'
, '0.10.35'
, '0.10.36'
, '0.10.37'
, '0.10.38'
, '0.10.39'
, '0.10.40'
, '0.11.0'
, '0.11.1'
, '0.11.2'
, '0.11.3'
, '0.11.4'
, '0.11.5'
, '0.11.6'
, '0.11.7'
, '0.11.8'
, '0.11.9'
, '0.11.10'
, '0.11.11'
, '0.11.12'
, '0.11.13'
, '0.11.14'
, '0.11.15'
, '0.11.16'
, '0.12.0'
, '0.12.1'
, '0.12.2'
, '0.12.3'
, '0.12.4'
, '0.12.5'
, '0.12.6'
, '0.12.7'
, '1.0.0'
, '1.0.1'
, '1.0.2'
, '1.0.3'
, '1.0.4'
, '1.1.0'
, '1.2.0'
, '1.3.0'
, '1.4.1'
, '1.4.2'
, '1.4.3'
, '1.5.0'
, '1.5.1'
, '1.6.0'
, '1.6.1'
, '1.6.2'
, '1.6.3'
, '1.6.4'
, '1.7.0'
, '1.7.1'
, '1.8.1'
, '1.8.2'
, '1.8.3'
, '1.8.4'
, '2.0.0'
, '2.0.1'
, '2.0.2'
, '2.1.0'
, '2.2.0'
, '2.2.1'
, '2.3.0'
, '2.3.1'
, '2.3.2'
, '2.3.3'
, '2.3.4'
, '2.4.0'
, '2.5.0'
, '3.0.0'
, '3.1.0'
, '3.2.0'
, '3.3.0'
, '3.3.1'
, '4.0.0'
, '4.1.0'
, '4.1.1'
, '4.1.2'
, '4.2.0'
, '4.2.1'
, '4.2.2'
, '5.0.0'
]
<|endoftext|>


<commit_before>var Semver = function(ver) {
  var segs = ver.split('.');
  return { major: (segs[0] || 0), minor: (segs[1] || 0), patch: (segs[2] || 0), version: ver };
};

var patch = function(to, from) {
  Object.keys(from).forEach(function(key){
    to[key] = from[key];
  });
  return to;
};

var JSONDeepEquals = function(o1, o2) {
  if (typeof o1 !== "object" || typeof o1 !== typeof o2 || o1 == null || o2 == null) {
    return o1 === o2;
  }

  var k1 = Object.keys(o1).sort();
  var k2 = Object.keys(o2).sort();
  if (k1.length != k2.length) return false;

  for (var i=0; i<k1.length; i++) {
    if (!JSONDeepEquals(o1[k1[i]], o2[k2[i]])) return false;
  }
  return true;
}

var prototype = Object.create(HTMLElement.prototype, {
  src: {
    get: function(){ return this.getAttribute('src') || 'about:blank'; }
  },

  editable: {
    get: function(){ return this.getAttribute('editable') == 'true'; }
  },

  env: {
    get: function(){ return this.readAttributeAsJson('data-environment'); }
  },

  config: {
    get: function(){ return this.readAttributeAsJson('data-config'); }
  },

  userstate: {
    get: function(){ return this.readAttributeAsJson('data-userstate'); }
  },

  debug: {
    get: function(){ return this.hasAttribute('debug'); }
  },

  apiVersion: {
    get: function(){
      if(!this._apiVersion) {
        this._apiVersion = new Semver(this.getAttribute('data-api-version') || '0.0.0');
      };
      return this._apiVersion;
    }
  }
});

prototype.readAttributeAsJson = function(name) {
  if(!this.hasAttribute(name)) { return {}; }
  return JSON.parse(this.getAttribute(name));
};

prototype.log = function(dir, event, data) {
  if(this.debug) { console.log(dir, event, data); }
};

prototype.attachedCallback = function(){
  this.iframe = document.createElement('iframe');
  this.iframe.src = this.src;
  this.iframe.addEventListener('message', this.handleMessage.bind(this));
  this.iframe.setAttribute('allowfullscreen', 'allowfullscreen');

  this.appendChild(this.iframe);
};

prototype.detachedCallback = function(){
  this.removeChild(this.iframe);
};

prototype.JSONAttributeHasChanged = function(oldAttribute, newAttribute) {
  return !JSONDeepEquals(JSON.parse(oldAttribute), JSON.parse(newAttribute));
};

prototype.attributeChangedCallback = function(name, oldAttribute, newAttribute){
  switch(name) {
    case 'editable':
      if (this.JSONAttributeHasChanged(oldAttribute, newAttribute)) {
        this.sendMessage('editableChanged', { editable: this.editable });
        if(this.apiVersion.minor < 1) {
          this.sendMessage('setEditable', { editable: this.editable });
        }
      }
      break;

    case 'data-config':
      if (this.JSONAttributeHasChanged(oldAttribute, newAttribute)) {
        this.sendMessage('attributesChanged', this.config);
      }
      break;

    case 'data-userstate':
      if (this.JSONAttributeHasChanged(oldAttribute, newAttribute)) {
        this.sendMessage('learnerStateChanged', this.userstate);
      }
      break;
  }
};

prototype.handleMessage = function(event) {
  if(event.detail.event) {
    var eventName = event.detail.event;
    var data = event.detail.data;

    this.log('↖', eventName, data);

    var handler = this.messageHandlers[eventName];
    if(handler) {
      handler.call(this, data);
    } else {
      console.error('Unknown event received: ' + eventName);
      this.error({message: 'Unknown event received: ' + eventName});
    }
  }
};

prototype.sendMessage = function(eventName, data) {
  var message = { event: eventName };
  if(data) { message.data = data; }
  if(this.iframe && this.iframe.contentWindow) {
    this.iframe.contentWindow.postMessage(message, '*');
    this.log('↘', message.event, message.data);
  }
};

prototype.fireCustomEvent = function(eventName, data, options) {
  options = options || {};
  var evt = new CustomEvent(eventName, { detail: data, bubbles: options.bubbles || false });
  this.dispatchEvent(evt);
};

prototype.messageHandlers = {
  startListening: function(){
    this.sendMessage('environmentChanged', this.env);
    this.sendMessage('attributesChanged', this.config);
    this.sendMessage('learnerStateChanged', this.userstate);
    this.sendMessage('editableChanged', { editable: this.editable });
  },

  setHeight: function(data){
    this.iframe.style.height = data.pixels + 'px';
  },

  setAttributes: function(data){
    var config = this.readAttributeAsJson('data-config');
    patch(config, data);
    this.setAttribute('data-config', JSON.stringify(config));

    // Player needs those events, until we have mutation observers in place
    this.fireCustomEvent('setAttributes', config);
  },

  setLearnerState: function(data) {
    var userstate = this.readAttributeAsJson('data-userstate');
    patch(userstate, data);
    this.setAttribute('data-userstate', JSON.stringify(userstate));

    // Player needs those events, until we have mutation observers in place
    this.fireCustomEvent('setLearnerState', userstate);
  },

  getPath: function(data) {
    console.warn('getPath/setPath are obsolete');
    var assetUrlTemplate = this.env && this.env.assetUrlTemplate;
    if(assetUrlTemplate) {
      var url = assetUrlTemplate.replace('<%= id %>', data.assetId );
      this.sendMessage('setPath', { url: url});
    }
  },

  setPropertySheetAttributes: function(data) { this.fireCustomEvent('setPropertySheetAttributes', data); },
  setEmpty: function(data) { this.fireCustomEvent('setEmpty', data); },
  track: function(data) { this.fireCustomEvent('track', data, {bubbles: true}); },
  error: function(data) { this.fireCustomEvent('error', data, {bubbles: true}); },
  changeBlocking: function(data) { this.fireCustomEvent('changeBlocking', data); },
  requestAsset: function(data) { this.fireCustomEvent('requestAsset', data); }
};

window.addEventListener('message', function(event){
  var iframes = document.querySelectorAll('versal-iframe-launcher > iframe');
  Array.prototype.forEach.call(iframes, function(iframe){
    if(iframe.contentWindow == event.source) {
      iframe.dispatchEvent(new CustomEvent('message', { detail: event.data }));
    }
  });
});

document.registerElement('versal-iframe-launcher', { prototype: prototype });
<commit_msg>Moved checking of attributes having changed to sendMessage<commit_after>var Semver = function(ver) {
  var segs = ver.split('.');
  return { major: (segs[0] || 0), minor: (segs[1] || 0), patch: (segs[2] || 0), version: ver };
};

var patch = function(to, from) {
  Object.keys(from).forEach(function(key){
    to[key] = from[key];
  });
  return to;
};

var JSONDeepEquals = function(o1, o2) {
  if (typeof o1 !== "object" || typeof o1 !== typeof o2 || o1 == null || o2 == null) {
    return o1 === o2;
  }

  var k1 = Object.keys(o1).sort();
  var k2 = Object.keys(o2).sort();
  if (k1.length != k2.length) return false;

  for (var i=0; i<k1.length; i++) {
    if (!JSONDeepEquals(o1[k1[i]], o2[k2[i]])) return false;
  }
  return true;
}

var prototype = Object.create(HTMLElement.prototype, {
  src: {
    get: function(){ return this.getAttribute('src') || 'about:blank'; }
  },

  editable: {
    get: function(){ return this.getAttribute('editable') == 'true'; }
  },

  env: {
    get: function(){ return this.readAttributeAsJson('data-environment'); }
  },

  config: {
    get: function(){ return this.readAttributeAsJson('data-config'); }
  },

  userstate: {
    get: function(){ return this.readAttributeAsJson('data-userstate'); }
  },

  debug: {
    get: function(){ return this.hasAttribute('debug'); }
  },

  apiVersion: {
    get: function(){
      if(!this._apiVersion) {
        this._apiVersion = new Semver(this.getAttribute('data-api-version') || '0.0.0');
      };
      return this._apiVersion;
    }
  }
});

prototype.readAttributeAsJson = function(name) {
  if(!this.hasAttribute(name)) { return {}; }
  return JSON.parse(this.getAttribute(name));
};

prototype.log = function(dir, event, data) {
  if(this.debug) { console.log(dir, event, data); }
};

prototype.createdCallback = function() {
  this._previousMessages = {}
};

prototype.attachedCallback = function(){
  this.iframe = document.createElement('iframe');
  this.iframe.src = this.src;
  this.iframe.addEventListener('message', this.handleMessage.bind(this));
  this.iframe.setAttribute('allowfullscreen', 'allowfullscreen');

  this.appendChild(this.iframe);
};

prototype.detachedCallback = function(){
  this.removeChild(this.iframe);
};

prototype.attributeChangedCallback = function(name, oldAttribute, newAttribute){
  switch(name) {
    case 'editable':
      this.sendMessage('editableChanged', { editable: this.editable });
      if(this.apiVersion.minor < 1) {
        this.sendMessage('setEditable', { editable: this.editable });
      }
      break;

    case 'data-config':
      this.sendMessage('attributesChanged', this.config);
      break;

    case 'data-userstate':
      this.sendMessage('learnerStateChanged', this.userstate);
      break;
  }
};

prototype.handleMessage = function(event) {
  if(event.detail.event) {
    var eventName = event.detail.event;
    var data = event.detail.data;

    this.log('↖', eventName, data);

    var handler = this.messageHandlers[eventName];
    if(handler) {
      handler.call(this, data);
    } else {
      console.error('Unknown event received: ' + eventName);
      this.error({message: 'Unknown event received: ' + eventName});
    }
  }
};

prototype.sendMessage = function(eventName, data) {
  if (JSONDeepEquals(this._previousMessages[eventName], data)) return;

  var message = { event: eventName };
  if(data) { message.data = data; }
  if(this.iframe && this.iframe.contentWindow) {
    this.iframe.contentWindow.postMessage(message, '*');
    this.log('↘', message.event, message.data);
    this._previousMessages[eventName] = data;
  }
};

prototype.fireCustomEvent = function(eventName, data, options) {
  options = options || {};
  var evt = new CustomEvent(eventName, { detail: data, bubbles: options.bubbles || false });
  this.dispatchEvent(evt);
};

prototype.messageHandlers = {
  startListening: function(){
    this.sendMessage('environmentChanged', this.env);
    this.sendMessage('attributesChanged', this.config);
    this.sendMessage('learnerStateChanged', this.userstate);
    this.sendMessage('editableChanged', { editable: this.editable });
  },

  setHeight: function(data){
    this.iframe.style.height = data.pixels + 'px';
  },

  setAttributes: function(data){
    var config = this.readAttributeAsJson('data-config');
    patch(config, data);
    this.setAttribute('data-config', JSON.stringify(config));

    // Player needs those events, until we have mutation observers in place
    this.fireCustomEvent('setAttributes', config);
  },

  setLearnerState: function(data) {
    var userstate = this.readAttributeAsJson('data-userstate');
    patch(userstate, data);
    this.setAttribute('data-userstate', JSON.stringify(userstate));

    // Player needs those events, until we have mutation observers in place
    this.fireCustomEvent('setLearnerState', userstate);
  },

  getPath: function(data) {
    console.warn('getPath/setPath are obsolete');
    var assetUrlTemplate = this.env && this.env.assetUrlTemplate;
    if(assetUrlTemplate) {
      var url = assetUrlTemplate.replace('<%= id %>', data.assetId );
      this.sendMessage('setPath', { url: url});
    }
  },

  setPropertySheetAttributes: function(data) { this.fireCustomEvent('setPropertySheetAttributes', data); },
  setEmpty: function(data) { this.fireCustomEvent('setEmpty', data); },
  track: function(data) { this.fireCustomEvent('track', data, {bubbles: true}); },
  error: function(data) { this.fireCustomEvent('error', data, {bubbles: true}); },
  changeBlocking: function(data) { this.fireCustomEvent('changeBlocking', data); },
  requestAsset: function(data) { this.fireCustomEvent('requestAsset', data); }
};

window.addEventListener('message', function(event){
  var iframes = document.querySelectorAll('versal-iframe-launcher > iframe');
  Array.prototype.forEach.call(iframes, function(iframe){
    if(iframe.contentWindow == event.source) {
      iframe.dispatchEvent(new CustomEvent('message', { detail: event.data }));
    }
  });
});

document.registerElement('versal-iframe-launcher', { prototype: prototype });
<|endoftext|>


<commit_before>const {send} = require('micro');
const fetch = require('node-fetch');
const assert = require('http-assert');

module.exports = async (req, res) => {
  let url = req.url.substr(1).split('?')[0];
  if (url === 'favicon.ico') return;
  if (url.indexOf('http://') !== -1) {
    url = url.substr(7);
  } else if (url.indexOf('https://') !== -1) {
    url = url.substr(8);
  }
  let json = req.url.indexOf('?json') !== -1;
  assert(url !== '', 400, 'URL must be defined. Usage: https://up.now.sh/google.com');
  let statusCode;
  let message;
  try {
    await fetch(`http://${url}`, {
      timeout: 5000
    });
    statusCode = 200;
    message = (json) ? ({url: url, status: 'Up'}) : (`${url} is up.`);
  } catch (err) {
    const {type, code} = err;
    if (type === 'system' && code === 'ENOTFOUND') {
      statusCode = 200;
      message = (json) ? ({url: url, status: 'Down'}) : (`${url} is not up.`);
    } else {
      statusCode = 400;
      message = (json) ? ({error: 'Something went wrong.'}) : (`Something went wrong.`);
    }
  }
  send(res, statusCode, message);
};
<commit_msg>Fix Content-Type<commit_after>const {send} = require('micro');
const fetch = require('node-fetch');
const assert = require('http-assert');

module.exports = async (req, res) => {
  let url = req.url.substr(1).split('?')[0];
  if (url === 'favicon.ico') return;
  if (url.indexOf('http://') !== -1) {
    url = url.substr(7);
  } else if (url.indexOf('https://') !== -1) {
    url = url.substr(8);
  }
  let json = req.url.indexOf('?json') !== -1;
  assert(url !== '', 400, 'URL must be defined. Usage: https://up.now.sh/google.com');
  let statusCode;
  let message;
  res.setHeader('Content-Type', 'application/json');
  try {
    await fetch(`http://${url}`, {
      timeout: 5000
    });
    statusCode = 200;
    if (json) {
      message = {url: url, status: 'Up'};
    } else {
      res.setHeader('Content-Type', 'text/plain');
      message = `${url} is up.`;
    }
  } catch (err) {
    const {type, code} = err;
    if (type === 'system' && code === 'ENOTFOUND') {
      statusCode = 200;
      message = (json) ? ({url: url, status: 'Down'}) : (`${url} is not up.`);
    } else {
      statusCode = 400;
      message = (json) ? ({error: 'Something went wrong.'}) : (`Something went wrong.`);
    }
  }
  send(res, statusCode, message);
};
<|endoftext|>


<commit_before>#! /usr/bin/env node

var fs      = require('fs')
var path    = require('path')
var os      = require('osenv')
var crypto  = require('crypto')

var mkdirp  = require('mkdirp')
var pull    = require('pull-stream')
var pt      = require('pull-traverse')
var paramap = require('pull-paramap')
var cont    = require('continuable')
var cpara   = require('continuable-hash')

//var _unpack  = require('npmd-unpack').unpack
var deps    = require('get-deps')
var clone   = require('clone')
var tarfs   = require('tar-fs')
var zlib    = require('zlib')

var EventEmitter = require('events').EventEmitter

function empty (obj) {
  for(var i in obj)
    return false
  return true
}

function emptyStream () {
  return function (abort, cb) {
    cb(true)
  }
}

function map (ob, iter) {
  if(Array.isArray(ob)) return ob.map(iter)
  var a = {}
  for(var k in ob)
    a[k] = iter(ob[k], k, ob)
  return a
}

function merge (a, b) {
  for(var k in b)
    if(!a[k])
      a[k] = b[k]
  return a
}

var tmpdir = os.tmpdir()

function randDir (pre) {
  return path.join(tmpdir, (pre || '') + Date.now() + '-' + Math.random())
}

function clean(tree) {

  function _clean (tree) {
    if(!tree) return tree
    delete tree.dependencies
    delete tree.devDependencies
    delete tree.optionalDependencies
    delete tree.peerDependencies
    return tree
  }

  if('string' === typeof tree.name)
    return _clean(tree)

  for(var k in tree)
    _clean(tree[k])

  return tree
}

var inject = module.exports = function (cache, config) {

  function unpack (pkg, opts, cb) {
    var start = Date.now()

    //get from the hash if it's already been downloaded!
    //else download from the registry or the url.
    var key = /\//.test(pkg.from) ? pkg.from : pkg.name + '@' + pkg.version
    var query = opts.hash === false ? key : {
      key: key,
      hash: pkg.shasum
    }

    return cache.createStream(query, function (err, stream) {
      if(err) return cb(err)
      if(!stream) throw new Error('did not return stream')
      var hash = crypto.createHash('sha1')

      stream
        .on('data', function (d) { hash.update(d) })
        .on('error', cb)
        .pipe(zlib.createGunzip())
        .on('error', function (err) {
          err.stack = 'attempting to gunzip: ' + key + '\n' + err.stack
          return cb(err)
        })
        .pipe(tarfs.extract(opts.target, {
          utimes: false,
          map: function (header) {
              header.name = header.name.replace(/^package\//, '')
              return header
            }
          }))
        .on('finish', function () {
          cb(null, hash.digest('hex'))
        })
    })
  }

  var installTree = cont.to(function(tree, opts, cb) {
    if(!cb)
      cb = opts, opts = {}

    //this only works on unix. in practice, you must pass in the config object.
    var cache = opts.cache || path.join(process.env.HOME, '.npm')

    var installPath = opts.path || process.cwd()

    tree.path = path.join(installPath, 'node_modules')

    pull(
      pt.widthFirst(tree, function (pkg) {
        if(!pkg.dependencies)
          return emptyStream()

        return pull(
          pull.values(pkg.dependencies),
          pull.map(function (_pkg) {
            _pkg.path = path.join(pkg.path, pkg.name, 'node_modules', _pkg.name)
            return _pkg
          })
        )
      }),
      paramap(function (pkg, cb) {
        unpack(pkg, {target: pkg.path}, function (err, hash) {

            if(err) return cb(err)
            if(hash !== pkg.shasum) return cb(new Error(
              'expected ' + pkg.name +'@' + pkg.version +'\n' +
              'to have shasum=' + pkg.shasum + ' but was='+hash))
            cb(err, pkg)
        })
      }, 32),
      pull.drain(null, cb)
    )

  })

  return cont.to(function (tree, opts, cb) {
    if(!cb) cb = opts, opts = {}

    if('string' === typeof tree.name)
      return installTree(tree, opts) (next)

    cpara(map(tree, function (tree) {
      return installTree(tree, opts)
    })) (next)

    function next (err) {
      cb(err, clean(clone(tree)))
    }
  })

}

//process.on is test for !browserify
if(!module.parent && process.on) {
  var config = require('npmd-config')
  var cache = require('npmd-cache')(config)
  var install = inject(cache)

  if(config.version) {
    console.log(require('./package').version)
    process.exit(0)
  }

  var b = ''
  process.stdin.on('data', function (data) {
    b += data.toString()
  })
  .on('end', function () {
    var tree = JSON.parse(b)
    install(tree, config, function (err, installed) {
      if(err) throw err
        console.log(JSON.stringify(installed, null, 2))
    })
  })
}

<commit_msg>install into correct paths<commit_after>#! /usr/bin/env node

var fs      = require('fs')
var path    = require('path')
var os      = require('osenv')
var crypto  = require('crypto')

var mkdirp  = require('mkdirp')
var pull    = require('pull-stream')
var pt      = require('pull-traverse')
var paramap = require('pull-paramap')
var cont    = require('continuable')
var cpara   = require('continuable-hash')

//var _unpack  = require('npmd-unpack').unpack
var deps    = require('get-deps')
var clone   = require('clone')
var tarfs   = require('tar-fs')
var zlib    = require('zlib')

var EventEmitter = require('events').EventEmitter

function empty (obj) {
  for(var i in obj)
    return false
  return true
}

function emptyStream () {
  return function (abort, cb) {
    cb(true)
  }
}

function map (ob, iter) {
  if(Array.isArray(ob)) return ob.map(iter)
  var a = {}
  for(var k in ob)
    a[k] = iter(ob[k], k, ob)
  return a
}

function merge (a, b) {
  for(var k in b)
    if(!a[k])
      a[k] = b[k]
  return a
}

var tmpdir = os.tmpdir()

function randDir (pre) {
  return path.join(tmpdir, (pre || '') + Date.now() + '-' + Math.random())
}

function clean(tree) {

  function _clean (tree) {
    if(!tree) return tree
    delete tree.dependencies
    delete tree.devDependencies
    delete tree.optionalDependencies
    delete tree.peerDependencies
    return tree
  }

  if('string' === typeof tree.name)
    return _clean(tree)

  for(var k in tree)
    _clean(tree[k])

  return tree
}

var inject = module.exports = function (cache, config) {

  function unpack (pkg, opts, cb) {
    var start = Date.now()

    //get from the hash if it's already been downloaded!
    //else download from the registry or the url.
    var key = /\//.test(pkg.from) ? pkg.from : pkg.name + '@' + pkg.version
    var query = opts.hash === false ? key : {
      key: key,
      hash: pkg.shasum
    }

    return cache.createStream(query, function (err, stream) {
      if(err) return cb(err)
      if(!stream) throw new Error('did not return stream')
      var hash = crypto.createHash('sha1')

      stream
        .on('data', function (d) { hash.update(d) })
        .on('error', cb)
        .pipe(zlib.createGunzip())
        .on('error', function (err) {
          err.stack = 'attempting to gunzip: ' + key + '\n' + err.stack
          return cb(err)
        })
        .pipe(tarfs.extract(opts.target, {
          utimes: false,
          map: function (header) {
              header.name = header.name.replace(/^package\//, '')
              return header
            }
          }))
        .on('finish', function () {
          cb(null, hash.digest('hex'))
        })
    })
  }

  var installTree = cont.to(function(tree, opts, cb) {
    if(!cb)
      cb = opts, opts = {}

    //this only works on unix. in practice, you must pass in the config object.
    var cache = opts.cache || path.join(process.env.HOME, '.npm')

    var installPath = opts.path || process.cwd()

    tree.path = (
      'string' === typeof tree.name
      ? path.join(installPath, 'node_modules', tree.name)
      : path.join(installPath, 'node_modules')
    )

    pull(
      pt.widthFirst(tree, function (pkg) {
        if(!pkg.dependencies)
          return emptyStream()

        return pull(
          pull.values(pkg.dependencies),
          pull.map(function (_pkg) {
            _pkg.path = path.join(pkg.path, 'node_modules', _pkg.name)
            return _pkg
          })
        )
      }),
      paramap(function (pkg, cb) {
        unpack(pkg, {target: pkg.path}, function (err, hash) {

            if(err) return cb(err)
            if(hash !== pkg.shasum) return cb(new Error(
              'expected ' + pkg.name +'@' + pkg.version +'\n' +
              'to have shasum=' + pkg.shasum + ' but was='+hash))
            cb(err, pkg)
        })
      }, 32),
      pull.drain(null, cb)
    )

  })

  return cont.to(function (tree, opts, cb) {
    if(!cb) cb = opts, opts = {}

    if('string' === typeof tree.name)
      return installTree(tree, opts) (next)

    cpara(map(tree, function (tree) {
      return installTree(tree, opts)
    })) (next)

    function next (err) {
      cb(err, clean(clone(tree)))
    }
  })

}

//process.on is test for !browserify
if(!module.parent && process.on) {
  var config = require('npmd-config')
  var cache = require('npmd-cache')(config)
  var install = inject(cache)

  if(config.version) {
    console.log(require('./package').version)
    process.exit(0)
  }

  var b = ''
  process.stdin.on('data', function (data) {
    b += data.toString()
  })
  .on('end', function () {
    var tree = JSON.parse(b)
    install(tree, config, function (err, installed) {
      if(err) throw err
        console.log(JSON.stringify(installed, null, 2))
    })
  })
}

<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';

import Header from './components/header'
import Registration from './components/registration'
import Options from './components/options'

const App = () => {
  let title = "Bedrift"
  return(

          <Registration title={ title } />
          <Options />

  )
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
)
<commit_msg>Added structure, removed redundant variable and changed quotation marks<commit_after>import React from 'react';
import ReactDOM from 'react-dom';

import Header from './components/header'
import Registration from './components/registration'
import Options from './components/options'

const App = () => {
  return(

            <Registration title={ 'Bedrift' } />

            <Options />

  )
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
)
<|endoftext|>


<commit_before>var fs = require('fs');

// we just wrap the shared code
var telehash = global.telehash = module.exports = require('./lib/mesh.js');

// node specific extensions
module.exports.add(require('telehash-udp4'));
module.exports.add(require('telehash-http'));
module.exports.add(require('telehash-tcp4'));
module.exports.add(require('telehash-webrtc'));

// attach our package+version to be helpful
module.exports.package = require('./package.json');

// wrap the mesh to accept file-based args
module.exports.load = function(args, cbMesh)
{
  var idFile, linksFile;

  // set up some node-specific things after the mesh is created
  function loaded(err)
  {
    if(err)
    {
      log.error(err);
      cbMesh(err);
      return false;
    }

    return telehash.mesh(args, function(err, mesh){
      if(!mesh) return cbMesh(err);

      // sync links automatically to file whenever they change
      if(linksFile) mesh.linked(function(json, str){
        log.debug('syncing links json',linksFile,str.length);
        fs.writeFileSync(linksFile, str);
      });

      cbMesh(err, mesh);
    });
  }

  if(typeof args.links == 'string')
  {
    linksFile = args.links;
    if(fs.existsSync(args.links))
    {
      log.debug('loading links',args.links);
      args.links = require(args.links);
    }
  }

  if(typeof args.id == 'string')
  {
    idFile = args.id;

    if(fs.existsSync(args.id))
    {
      log.debug('loading id',args.id);
      var err;
      try{
        args.id = JSON.parse(fs.readFileSync(args.id));
      }catch(E){
        err = E;
      }
      return loaded(err);
    }

    // create new
    log.debug('generating new id');
    telehash.generate(function(err,id){
      if(err) return loaded(err);
      args.id = id;
      log.debug('saving to',idFile);
      fs.writeFile(idFile, JSON.stringify(id, null, 4), loaded);
    });

    return;
  }

  // default passthrough
  return loaded();
}
<commit_msg>add log to index<commit_after>var fs = require('fs');
var log = require("./lib/util/log.js")("index")

// we just wrap the shared code
var telehash = global.telehash = module.exports = require('./lib/mesh.js');

// node specific extensions
module.exports.add(require('telehash-udp4'));
module.exports.add(require('telehash-http'));
module.exports.add(require('telehash-tcp4'));
module.exports.add(require('telehash-webrtc'));

// attach our package+version to be helpful
module.exports.package = require('./package.json');

// wrap the mesh to accept file-based args
module.exports.load = function(args, cbMesh)
{
  var idFile, linksFile;

  // set up some node-specific things after the mesh is created
  function loaded(err)
  {
    if(err)
    {
      log.error(err);
      cbMesh(err);
      return false;
    }

    return telehash.mesh(args, function(err, mesh){
      if(!mesh) return cbMesh(err);

      // sync links automatically to file whenever they change
      if(linksFile) mesh.linked(function(json, str){
        log.debug('syncing links json',linksFile,str.length);
        fs.writeFileSync(linksFile, str);
      });

      cbMesh(err, mesh);
    });
  }

  if(typeof args.links == 'string')
  {
    linksFile = args.links;
    if(fs.existsSync(args.links))
    {
      log.debug('loading links',args.links);
      args.links = require(args.links);
    }
  }

  if(typeof args.id == 'string')
  {
    idFile = args.id;

    if(fs.existsSync(args.id))
    {
      log.debug('loading id',args.id);
      var err;
      try{
        args.id = JSON.parse(fs.readFileSync(args.id));
      }catch(E){
        err = E;
      }
      return loaded(err);
    }

    // create new
    log.debug('generating new id');
    telehash.generate(function(err,id){
      if(err) return loaded(err);
      args.id = id;
      log.debug('saving to',idFile);
      fs.writeFile(idFile, JSON.stringify(id, null, 4), loaded);
    });

    return;
  }

  // default passthrough
  return loaded();
}
<|endoftext|>


<commit_before>'use strict';

var each = require('each-async');
var fs = require('fs-extra');
var path = require('path');
var Ware = require('ware');

/**
 * Initialize Decompress
 *
 * @api public
 */

function Decompress() {
    this.ware = new Ware();
}

/**
 * Add a plugin to the middleware stack
 *
 * @param {Function} plugin
 * @api public
 */

Decompress.prototype.use = function (plugin) {
    this.ware.use(plugin);
    return this;
};

/**
 * Get or set the source file
 *
 * @param {String|Buffer} file
 * @api public
 */

Decompress.prototype.src = function (file) {
    if (!arguments.length) {
        return this._src;
    }

    this._src = file;
    return this;
};

/**
 * Get or set the destination path
 *
 * @param {String} path
 * @api public
 */

Decompress.prototype.dest = function (path) {
    if (!arguments.length) {
        return this._dest;
    }

    this._dest = path;
    return this;
};

/**
 * Decompress archive
 *
 * @param {Function} cb
 * @api public
 */

Decompress.prototype.decompress = function (cb) {
    cb = cb || function () {};
    var self = this;

    this.read(function (err, file) {
        if (!file || file.contents.length === 0) {
            return cb();
        }

        self.run(file, function (err) {
            if (err) {
                return cb(err);
            }

            self.write(self.files, function (err) {
                cb(err, file);
            });
        });
    });
};

/**
 * Run a file through the middleware
 *
 * @param {Object} file
 * @param {Function} cb
 * @api public
 */

Decompress.prototype.run = function (file, cb) {
    this.ware.run(file, this, cb);
};

/**
 * Read the archive
 *
 * @param {Function} cb
 * @api public
 */

Decompress.prototype.read = function (cb) {
    var file = {};
    var src = this.src();

    if (Buffer.isBuffer(src)) {
        file.contents = src;

        return cb(null, file);
    }

    fs.readFile(src, function (err, buf) {
        if (err) {
            return cb(err);
        }

        file.contents = buf;
        file.path = src;

        cb(null, file);
    });
};

/**
 * Write files to destination
 *
 * @param {Array} files
 * @param {Function} cb
 * @api public
 */

Decompress.prototype.write = function (files, cb) {
    var dest = this.dest();

    if (!dest) {
        return cb();
    }

    each(files, function (file, i, done) {
        fs.outputFile(path.join(dest, file.path), file.contents, function (err) {
            done(err);
        });
    }, function (err) {
        if (err) {
            return cb(err);
        }

        cb();
    });
};

/**
 * Module exports
 */

module.exports = Decompress;
module.exports.tar = require('decompress-tar');
module.exports.targz = require('decompress-targz');
module.exports.zip = require('decompress-unzip');
<commit_msg>Check for errors<commit_after>'use strict';

var each = require('each-async');
var fs = require('fs-extra');
var path = require('path');
var Ware = require('ware');

/**
 * Initialize Decompress
 *
 * @api public
 */

function Decompress() {
    this.ware = new Ware();
}

/**
 * Add a plugin to the middleware stack
 *
 * @param {Function} plugin
 * @api public
 */

Decompress.prototype.use = function (plugin) {
    this.ware.use(plugin);
    return this;
};

/**
 * Get or set the source file
 *
 * @param {String|Buffer} file
 * @api public
 */

Decompress.prototype.src = function (file) {
    if (!arguments.length) {
        return this._src;
    }

    this._src = file;
    return this;
};

/**
 * Get or set the destination path
 *
 * @param {String} path
 * @api public
 */

Decompress.prototype.dest = function (path) {
    if (!arguments.length) {
        return this._dest;
    }

    this._dest = path;
    return this;
};

/**
 * Decompress archive
 *
 * @param {Function} cb
 * @api public
 */

Decompress.prototype.decompress = function (cb) {
    cb = cb || function () {};
    var self = this;

    this.read(function (err, file) {
        if (!file || file.contents.length === 0) {
            return cb();
        }

        if (err) {
            return cb(err);
        }

        self.run(file, function (err) {
            if (err) {
                return cb(err);
            }

            self.write(self.files, function (err) {
                cb(err, file);
            });
        });
    });
};

/**
 * Run a file through the middleware
 *
 * @param {Object} file
 * @param {Function} cb
 * @api public
 */

Decompress.prototype.run = function (file, cb) {
    this.ware.run(file, this, cb);
};

/**
 * Read the archive
 *
 * @param {Function} cb
 * @api public
 */

Decompress.prototype.read = function (cb) {
    var file = {};
    var src = this.src();

    if (Buffer.isBuffer(src)) {
        file.contents = src;
        return cb(null, file);
    }

    fs.readFile(src, function (err, buf) {
        if (err) {
            return cb(err);
        }

        file.contents = buf;
        file.path = src;

        cb(null, file);
    });
};

/**
 * Write files to destination
 *
 * @param {Array} files
 * @param {Function} cb
 * @api public
 */

Decompress.prototype.write = function (files, cb) {
    var dest = this.dest();

    if (!dest) {
        return cb();
    }

    each(files, function (file, i, done) {
        fs.outputFile(path.join(dest, file.path), file.contents, function (err) {
            done(err);
        });
    }, function (err) {
        if (err) {
            return cb(err);
        }

        cb();
    });
};

/**
 * Module exports
 */

module.exports = Decompress;
module.exports.tar = require('decompress-tar');
module.exports.targz = require('decompress-targz');
module.exports.zip = require('decompress-unzip');
<|endoftext|>