apollo-nico
Version:
对 nico 及 apollo-theme 的封装,方便跨平台使用
207 lines (183 loc) • 4.51 kB
JavaScript
var fs = require('fs'),
path = require('path'),
util = require('./util');
// Match "\".
var PATTERN_BACKSLASH = /\\/g,
// Extnames of text file.
text = [ '.js', '.css', '.json', '.txt', '.tpl', '.xml' ],
/**
* Remove all contents in a directory.
* @root {string}
* @param [pathname] {string}
*/
emptyDir = exports.emptyDir = function (root, pathname) {
// Remove contents.
readDir(root, pathname || '.', true).data.forEach(function (pathname) {
if (stat(root, pathname) === 'dir') {
emptyDir(root, pathname);
} else {
fs.unlinkSync(path.join(root, pathname));
}
});
// Remove self.
fs.rmdirSync(path.join(root, pathname || '.'));
},
/**
* List directory and sub directories.
* @param root {string}
* @param [pathname] {string}
* @return {Object}
*/
listDir = exports.listDir = function (root, pathname) {
var result = {};
readDir(root, pathname || '.').data.forEach(function (pathname) {
if (stat(root, pathname) === 'dir') {
result[pathname] = true; // Is a directory.
util.mix(result, listDir(root, pathname)); // List sub directory.
} else {
result[pathname] = false; // Not a directory.
}
});
return result;
},
/**
* Make directory and all parents.
* @param pathname {string}
*/
makeDir = exports.makeDir = function (root, pathname) {
(function next(pathname) {
if (!fs.existsSync(pathname)) {
// At first, make parent directory.
next(path.resolve(pathname, '..'));
// Then, make current directory.
fs.mkdirSync(pathname);
}
}(path.join(root, pathname)));
},
/**
* Mix two directories.
* @param target {string}
* @param source {string}
*/
mixDir = exports.mixDir = function (target, source) {
util.each(listDir(source), function (isDir, pathname) {
if (isDir) {
makeDir(target, pathname);
} else {
writeFile(target, readFile(source, pathname));
}
});
},
/**
* Read a directory.
* @param root {string}
* @param pathname {string}
* @param [all] {boolean}
* @return {Object}
*/
readDir = exports.readDir = function (root, pathname, all) {
var file = {
get data() {
if (!this._data) {
this._data = fs
.readdirSync(path.join(root, pathname))
.filter(function (name) { // Ignore hidden items.
return all || name[0] !== '.'
})
.map(function (name) {
return path.join(pathname, name)
.replace(PATTERN_BACKSLASH, '/');
});
}
return this._data;
},
set data(data) {
this._data = data;
},
meta: {},
pathname: pathname,
type: '/'
};
return file;
},
/**
* Read a file.
* @param root {string}
* @param pathname {string}
* @param [type] {string}
* @return {Object}
*/
readFile = exports.readFile = function (root, pathname, type) {
var file = {
get data() {
if (!this._data) {
this._data = fs.readFileSync(path.join(root, pathname));
if (text.indexOf(this.type) !== -1) {
decode(this);
}
}
return this._data;
},
set data(data) {
this._data = data;
},
meta: {},
pathname: pathname,
type: type || path.extname(pathname)
};
return file;
},
/**
* Determine file or directory.
* @param root {string}
* @param pathname {string}
* @return {string|null}
*/
stat = exports.stat = function (root, pathname) {
var fullPath = path.join(root, pathname);
if (fs.existsSync(fullPath)) {
if (fs.statSync(fullPath).isDirectory()) {
return 'dir';
} else {
return 'file';
}
} else {
return null;
}
},
/**
* Write file or directory.
* @param root {string}
* @param file {Object}
*/
writeFile = exports.writeFile = function (root, file) {
var fullPath = path.join(root, file.pathname);
makeDir(root, path.dirname(file.pathname)); // Ensure container.
if (text.indexOf(file.type) !== -1) {
encode(file);
}
fs.writeFileSync(fullPath, file.data);
},
/**
* Decode text file.
* @param file {Object}
*/
decode = function (file) {
if (text.indexOf(file.type) !== -1) {
var data = file.data;
if (data.length > 2 && !(data[0] ^ 0xEF) && !(data[1] ^ 0xBB) && !(data[2] ^ 0xBF)) {
// Remove UTF-8 BOM.
data = data.slice(3);
}
file.data = data.toString('binary');
}
},
/**
* Encode text file.
* @param file {Object}
*/
encode = function (file) {
if (text.indexOf(file.type) !== -1) {
file.data = new Buffer(file.data, 'binary');
}
};