UNPKG

enb

Version:

Faster BEM/BEViS assembler

249 lines (234 loc) 8.29 kB
/** * FileList * ======== */ var fs = require('fs'); var vowFs = require('./fs/async-fs'); var Vow = require('vow'); var inherit = require('inherit'); var path = require('path'); /** * FileList — класс для работы со списком файлов. * Умеет быстро выдавать файлы по суффиксу. * @name FileList * @class */ module.exports = inherit({ /** * Конструктор. */ __constructor: function () { this.items = []; this.slices = []; this.bySuffix = {}; }, /** * Добавляет файлы в FileList. * Каждый файл описывается в виде: * { fullname: <абсолютный путь к файлу>, name: <имя файла>, suffix: <суффикс>, mtime: <время изменения> } * @param {Object[]} files */ addFiles: function (files) { this.slices.push(files); for (var i = 0, l = files.length; i < l; i++) { var file = files[i]; this.items.push(file); (this.bySuffix[file.suffix] || (this.bySuffix[file.suffix] = [])).push(file); } }, /** * Возвращает файлы по суффиксу. * Каждый файл описывается в виде: * { fullname: <абсолютный путь к файлу>, name: <имя файла>, suffix: <суффикс>, mtime: <время изменения> } * @param {String|String[]} suffix. * @returns {Object[]} */ getBySuffix: function (suffix) { if (Array.isArray(suffix) && suffix.length === 1) { suffix = suffix[0]; } if (Array.isArray(suffix)) { var res = []; this.slices.forEach(function (slice) { suffix.forEach(function (s) { for (var i = 0, l = slice.length; i < l; i++) { var file = slice[i]; if (file.suffix === s) { res.push(file); } } }); }); return res; } else { return this.bySuffix[suffix] || []; } }, /** * Возвращает файлы по имени. * Каждый файл описывается в виде: * { fullname: <абсолютный путь к файлу>, name: <имя файла>, suffix: <суффикс>, mtime: <время изменения> } * @param {String} name. * @returns {Object[]} */ getByName: function (name) { return this.items.filter(function (file) { return file.name === name; }); }, /** * Синхронно загружает список файлов из директории. * @param {String} dirname Абсолютный путь к директории. * @param {Boolean} recursive Рекурсивная загрузка. */ loadFromDirSync: function (dirname, recursive) { var files = []; var _this = this; filterFiles(fs.readdirSync(dirname)).forEach(function (filename) { var fullname = path.join(dirname, filename); var stat = fs.statSync(fullname); if (stat.isFile()) { files.push({ name: filename, fullname: fullname, suffix: getSuffix(filename), mtime: stat.mtime.getTime() }); } else if (stat.isDirectory()) { if (recursive) { _this.loadFromDirSync(fullname, recursive); } } }); this.addFiles(files); }, /** * Асинхронно загружает список файлов из директории. * @param {String} dirname Абсолютный путь к директории. * @param {Boolean} recursive Рекурсивная загрузка. * @returns {Promise} */ loadFromDir: function (dirname, recursive) { var _this = this; return this._loadFromDir(dirname, recursive).then(function (files) { _this.addFiles(files); }); }, /** * Асинхронно загружает список файлов из директории. * @param {String} dirname * @param {Boolean} recursive * @returns {Promise} * @private */ _loadFromDir: function (dirname, recursive) { var _this = this; return vowFs.listDir(dirname).then(function (filenames) { return Vow.all(filenames.map(function (filename) { var fullname = path.join(dirname, filename); return vowFs.stat(fullname).then(function (stat) { if (stat.isFile()) { return [{ name: filename, fullname: fullname, suffix: getSuffix(filename), mtime: stat.mtime.getTime() }]; } else if (stat.isDirectory()) { if (recursive) { return _this._loadFromDir(fullname, recursive); } } return []; }); })); }).then(function (fileLists) { return [].concat.apply([], fileLists); }); }, /** * Разбирает имя файла, извлекая данные BEM-сущности. * Формат ответа: * { * filenameWithoutSuffix: <имя файла без суффикса>, * suffix: <суффикс>, * bem: { * block: ..., * elem: ..., * modName: ..., * modVal: ... * }, * bemdecl: <bemdecl-формат> * }; * @returns {Object} */ parseFilename: parseFilename, /** * Возвращает информацию о файле в виде: * { fullname: <абсолютный путь к файлу>, name: <имя файла>, suffix: <суффикс>, mtime: <время изменения> } */ getFileInfo: getFileInfo }, { parseFilename: parseFilename, getFileInfo: getFileInfo }); function getFileInfo(filename) { var baseName = path.basename(filename); var suffix = baseName.split('.').slice(1).join('.'); var stat = fs.statSync(filename); return { name: baseName, fullname: filename, suffix: suffix, mtime: stat.mtime.getTime(), isDirectory: stat.isDirectory() }; } function parseFilename(filename) { var filenameParts = filename.split('.'); var filenameWithoutSuffix = filenameParts[0]; var suffix = filenameParts.slice(1).join('.'); var bem = {}; var modParts; if (~filenameWithoutSuffix.indexOf('__')) { var blockElemParts = filenameWithoutSuffix.split('__'); bem.block = blockElemParts[0]; var elemParts = blockElemParts[1].split('_'); bem.elem = elemParts[0]; modParts = elemParts.slice(1); } else { var blockParts = filenameWithoutSuffix.split('_'); bem.block = blockParts[0]; modParts = blockParts.slice(1); } if (modParts.length) { bem.modName = modParts[0]; bem.modVal = modParts[1] || ''; } var bemdecl = { name: bem.block }; if (bem.elem) { if (bem.modName) { bemdecl.elems = [{ name: bem.elem, mods: [{ name: bem.modName, vals: [ {name: bem.modVal} ] }]}]; } else { bemdecl.elems = [{ name: bem.elem }]; } } else if (bem.modName) { bemdecl.mods = [{ name: bem.modName, vals: [ {name: bem.modVal} ] }]; } return { filenameWithoutSuffix: filenameWithoutSuffix, suffix: suffix, bem: bem, bemdecl: bemdecl }; } function filterFiles(filenames) { return filenames.filter(function (filename) { return filename.charAt(0) !== '.'; }); } function getSuffix(filename) { return filename.split('.').slice(1).join('.'); }