You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
657 lines
19 KiB
657 lines
19 KiB
// Generated by CoffeeScript 1.6.3
|
|
var Backbone, FileModel, Iconv, Model, TaskGroup, balUtil, docpadUtil, extendr, extractOptsAndCallback, jschardet, mime, pathUtil, safefs, typeChecker, _ref, _ref1,
|
|
__hasProp = {}.hasOwnProperty,
|
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
|
__slice = [].slice;
|
|
|
|
pathUtil = require('path');
|
|
|
|
balUtil = require('bal-util');
|
|
|
|
typeChecker = require('typechecker');
|
|
|
|
TaskGroup = require('taskgroup').TaskGroup;
|
|
|
|
safefs = require('safefs');
|
|
|
|
mime = require('mime');
|
|
|
|
extendr = require('extendr');
|
|
|
|
extractOptsAndCallback = require('extract-opts').extractOptsAndCallback;
|
|
|
|
jschardet = null;
|
|
|
|
Iconv = null;
|
|
|
|
_ref = require('../base'), Backbone = _ref.Backbone, Model = _ref.Model;
|
|
|
|
docpadUtil = require('../util');
|
|
|
|
FileModel = (function(_super) {
|
|
__extends(FileModel, _super);
|
|
|
|
function FileModel() {
|
|
_ref1 = FileModel.__super__.constructor.apply(this, arguments);
|
|
return _ref1;
|
|
}
|
|
|
|
FileModel.prototype.klass = FileModel;
|
|
|
|
FileModel.prototype.type = 'file';
|
|
|
|
FileModel.prototype.outDirPath = null;
|
|
|
|
FileModel.prototype.detectEncoding = false;
|
|
|
|
FileModel.prototype.stat = null;
|
|
|
|
FileModel.prototype.data = null;
|
|
|
|
FileModel.prototype.buffer = null;
|
|
|
|
FileModel.prototype.meta = null;
|
|
|
|
FileModel.prototype.getOpts = function() {
|
|
return {
|
|
outDirPath: this.outDirPath,
|
|
detectEncoding: this.detectEncoding,
|
|
stat: this.stat,
|
|
data: this.data,
|
|
buffer: this.buffer,
|
|
meta: this.meta
|
|
};
|
|
};
|
|
|
|
FileModel.prototype.clone = function() {
|
|
var attrs, instance, opts;
|
|
opts = this.getOpts();
|
|
attrs = this.getAttributes();
|
|
instance = new this.klass(attrs, opts);
|
|
instance._events = extendr.deepExtend(this._events);
|
|
return instance;
|
|
};
|
|
|
|
FileModel.prototype.defaults = {
|
|
id: null,
|
|
basename: null,
|
|
outBasename: null,
|
|
extension: null,
|
|
outExtension: null,
|
|
extensions: null,
|
|
filename: null,
|
|
fullPath: null,
|
|
fullDirPath: null,
|
|
outPath: null,
|
|
outDirPath: null,
|
|
outFilename: null,
|
|
relativePath: null,
|
|
relativeOutPath: null,
|
|
relativeDirPath: null,
|
|
relativeOutDirPath: null,
|
|
relativeBase: null,
|
|
releativeOutBase: null,
|
|
contentType: null,
|
|
outContentType: null,
|
|
ctime: null,
|
|
mtime: null,
|
|
exists: null,
|
|
encoding: null,
|
|
source: null,
|
|
content: null,
|
|
title: null,
|
|
name: null,
|
|
date: null,
|
|
slug: null,
|
|
url: null,
|
|
urls: null,
|
|
ignored: false,
|
|
standalone: false
|
|
};
|
|
|
|
FileModel.prototype.setData = function(data) {
|
|
this.data = data;
|
|
return this;
|
|
};
|
|
|
|
FileModel.prototype.getData = function() {
|
|
return this.data;
|
|
};
|
|
|
|
FileModel.prototype.setBuffer = function(buffer) {
|
|
this.buffer = buffer;
|
|
return this;
|
|
};
|
|
|
|
FileModel.prototype.getBuffer = function() {
|
|
return this.buffer;
|
|
};
|
|
|
|
FileModel.prototype.setStat = function(stat) {
|
|
this.stat = stat;
|
|
this.set({
|
|
ctime: new Date(stat.ctime),
|
|
mtime: new Date(stat.mtime)
|
|
});
|
|
return this;
|
|
};
|
|
|
|
FileModel.prototype.getStat = function() {
|
|
return this.stat;
|
|
};
|
|
|
|
FileModel.prototype.getAttributes = function() {
|
|
var attrs;
|
|
attrs = this.toJSON();
|
|
attrs = extendr.dereference(attrs);
|
|
return attrs;
|
|
};
|
|
|
|
FileModel.prototype.toJSON = function() {
|
|
var data;
|
|
data = FileModel.__super__.toJSON.apply(this, arguments);
|
|
data.meta = this.getMeta().toJSON();
|
|
return data;
|
|
};
|
|
|
|
FileModel.prototype.getMeta = function() {
|
|
var args, _ref2;
|
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
if (this.meta === null) {
|
|
this.meta = new Model();
|
|
}
|
|
if (args.length) {
|
|
return (_ref2 = this.meta).get.apply(_ref2, args);
|
|
} else {
|
|
return this.meta;
|
|
}
|
|
};
|
|
|
|
FileModel.prototype.setMeta = function(attrs) {
|
|
var _ref2;
|
|
attrs = (_ref2 = typeof attrs.toJSON === "function" ? attrs.toJSON() : void 0) != null ? _ref2 : attrs;
|
|
this.getMeta().set(attrs);
|
|
this.set(attrs);
|
|
return this;
|
|
};
|
|
|
|
FileModel.prototype.setMetaDefaults = function(defaults) {
|
|
this.getMeta().setDefaults(defaults);
|
|
this.setDefaults(defaults);
|
|
return this;
|
|
};
|
|
|
|
FileModel.prototype.getFilename = function(_arg) {
|
|
var filePath, filename, fullPath, relativePath;
|
|
filename = _arg.filename, fullPath = _arg.fullPath, relativePath = _arg.relativePath;
|
|
filename || (filename = this.get('filename'));
|
|
if (!filename) {
|
|
filePath = this.get('fullPath') || this.get('relativePath');
|
|
if (filePath) {
|
|
filename = pathUtil.basename(filePath);
|
|
}
|
|
}
|
|
return filename || null;
|
|
};
|
|
|
|
FileModel.prototype.getExtensions = function(_arg) {
|
|
var extensions, filename;
|
|
extensions = _arg.extensions, filename = _arg.filename;
|
|
extensions || (extensions = this.get('extensions') || null);
|
|
if ((extensions || []).length === 0) {
|
|
filename = this.getFilename({
|
|
filename: filename
|
|
});
|
|
if (filename) {
|
|
extensions = docpadUtil.getExtensions(filename);
|
|
}
|
|
}
|
|
return extensions || null;
|
|
};
|
|
|
|
FileModel.prototype.getContent = function() {
|
|
return this.get('content') || this.getBuffer();
|
|
};
|
|
|
|
FileModel.prototype.getOutContent = function() {
|
|
return this.getContent();
|
|
};
|
|
|
|
FileModel.prototype.isText = function() {
|
|
return this.get('encoding') !== 'binary';
|
|
};
|
|
|
|
FileModel.prototype.isBinary = function() {
|
|
return this.get('encoding') === 'binary';
|
|
};
|
|
|
|
FileModel.prototype.setUrl = function(url) {
|
|
this.addUrl(url);
|
|
this.set({
|
|
url: url
|
|
});
|
|
return this;
|
|
};
|
|
|
|
FileModel.prototype.addUrl = function(url) {
|
|
var existingUrl, found, newUrl, urls, _i, _j, _len, _len1;
|
|
if (url instanceof Array) {
|
|
for (_i = 0, _len = url.length; _i < _len; _i++) {
|
|
newUrl = url[_i];
|
|
this.addUrl(newUrl);
|
|
}
|
|
} else if (url) {
|
|
found = false;
|
|
urls = this.get('urls');
|
|
for (_j = 0, _len1 = urls.length; _j < _len1; _j++) {
|
|
existingUrl = urls[_j];
|
|
if (existingUrl === url) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
urls.push(url);
|
|
}
|
|
this.trigger('change:urls', this, urls, {});
|
|
this.trigger('change', this, {});
|
|
}
|
|
return this;
|
|
};
|
|
|
|
FileModel.prototype.removeUrl = function(userUrl) {
|
|
var index, url, urls, _i, _len;
|
|
urls = this.get('urls');
|
|
for (index = _i = 0, _len = urls.length; _i < _len; index = ++_i) {
|
|
url = urls[index];
|
|
if (url === userUrl) {
|
|
urls.splice(index, 1);
|
|
break;
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
|
|
FileModel.prototype.getPath = function(relativePath, parentPath) {
|
|
var path, relativeDirPath;
|
|
if (/^\./.test(relativePath)) {
|
|
relativeDirPath = this.get('relativeDirPath');
|
|
path = pathUtil.join(relativeDirPath, relativePath);
|
|
} else {
|
|
if (parentPath) {
|
|
path = pathUtil.join(parentPath, relativePath);
|
|
} else {
|
|
path = relativePath;
|
|
}
|
|
}
|
|
return path;
|
|
};
|
|
|
|
FileModel.prototype.initialize = function(attrs, opts) {
|
|
var buffer, data, defaults, detectEncoding, meta, outDirPath, stat;
|
|
if (opts == null) {
|
|
opts = {};
|
|
}
|
|
outDirPath = opts.outDirPath, detectEncoding = opts.detectEncoding, stat = opts.stat, data = opts.data, buffer = opts.buffer, meta = opts.meta;
|
|
if (detectEncoding != null) {
|
|
this.detectEncoding = detectEncoding;
|
|
}
|
|
if (outDirPath) {
|
|
this.outDirPath = outDirPath;
|
|
}
|
|
defaults = {
|
|
extensions: [],
|
|
urls: [],
|
|
id: this.cid
|
|
};
|
|
if (stat) {
|
|
this.setStat(stat);
|
|
} else {
|
|
defaults.ctime = new Date();
|
|
defaults.mtime = new Date();
|
|
}
|
|
this.set(defaults);
|
|
if (attrs.data != null) {
|
|
data = attrs.data;
|
|
delete attrs.data;
|
|
delete this.attributes.data;
|
|
}
|
|
if (data != null) {
|
|
this.setData(data);
|
|
}
|
|
if (attrs.buffer != null) {
|
|
buffer = attrs.buffer;
|
|
delete attrs.buffer;
|
|
delete this.attributes.buffer;
|
|
}
|
|
if (buffer != null) {
|
|
this.setBuffer(buffer);
|
|
}
|
|
if (attrs.meta != null) {
|
|
this.setMeta(attrs.meta);
|
|
delete attrs.meta;
|
|
}
|
|
if (meta) {
|
|
this.setMeta(meta);
|
|
}
|
|
return FileModel.__super__.initialize.apply(this, arguments);
|
|
};
|
|
|
|
FileModel.prototype.load = function(opts, next) {
|
|
var buffer, data, exists, file, filePath, fullPath, tasks, _ref2, _ref3,
|
|
_this = this;
|
|
if (opts == null) {
|
|
opts = {};
|
|
}
|
|
_ref2 = extractOptsAndCallback(opts, next), opts = _ref2[0], next = _ref2[1];
|
|
file = this;
|
|
exists = (_ref3 = opts.exists) != null ? _ref3 : false;
|
|
fullPath = this.get('fullPath');
|
|
filePath = fullPath || this.get('relativePath') || this.get('filename');
|
|
file.log('debug', "Loading the file: " + filePath);
|
|
tasks = new TaskGroup().setConfig({
|
|
concurrency: 0
|
|
}).once('complete', function(err) {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
file.log('debug', "Loaded the file: " + filePath);
|
|
return file.parse(function(err) {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
return file.normalize(function(err) {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
return next(null, file.buffer);
|
|
});
|
|
});
|
|
});
|
|
data = file.getData();
|
|
if (data != null) {
|
|
buffer = new Buffer(data);
|
|
file.setBuffer(buffer);
|
|
}
|
|
if (opts.stat) {
|
|
file.setStat(opts.stat);
|
|
}
|
|
if (opts.buffer) {
|
|
file.setBuffer(opts.buffer);
|
|
}
|
|
tasks.addTask(function(complete) {
|
|
if (fullPath && exists && (opts.stat != null) === false) {
|
|
return safefs.stat(fullPath, function(err, fileStat) {
|
|
if (err) {
|
|
return complete(err);
|
|
}
|
|
file.setStat(fileStat);
|
|
return complete();
|
|
});
|
|
} else {
|
|
return complete();
|
|
}
|
|
});
|
|
tasks.addTask(function(complete) {
|
|
if (fullPath && exists && (opts.buffer != null) === false) {
|
|
return safefs.readFile(fullPath, function(err, buffer) {
|
|
if (err) {
|
|
return complete(err);
|
|
}
|
|
file.setBuffer(buffer);
|
|
return complete();
|
|
});
|
|
} else {
|
|
return complete();
|
|
}
|
|
});
|
|
if (fullPath) {
|
|
safefs.exists(fullPath, function(_exists) {
|
|
exists = _exists;
|
|
file.set({
|
|
exists: exists
|
|
});
|
|
return tasks.run();
|
|
});
|
|
} else {
|
|
tasks.run();
|
|
}
|
|
return this;
|
|
};
|
|
|
|
FileModel.prototype.parse = function(opts, next) {
|
|
var buffer, changes, content, encoding, err, fullPath, isText, source, _ref2, _ref3, _ref4;
|
|
if (opts == null) {
|
|
opts = {};
|
|
}
|
|
_ref2 = extractOptsAndCallback(opts, next), opts = _ref2[0], next = _ref2[1];
|
|
buffer = this.getBuffer();
|
|
fullPath = this.get('fullPath');
|
|
encoding = this.get('encoding') || null;
|
|
changes = {};
|
|
if ((encoding != null) === false || opts.reencode === true) {
|
|
isText = balUtil.isTextSync(fullPath, buffer);
|
|
if (isText === true) {
|
|
if (this.detectEncoding) {
|
|
if (jschardet == null) {
|
|
jschardet = require('jschardet');
|
|
}
|
|
try {
|
|
if (Iconv == null) {
|
|
Iconv = require('iconv').Iconv;
|
|
}
|
|
} catch (_error) {
|
|
err = _error;
|
|
Iconv = null;
|
|
}
|
|
if (encoding == null) {
|
|
encoding = ((_ref3 = jschardet.detect(buffer)) != null ? _ref3.encoding : void 0) || 'utf8';
|
|
}
|
|
} else {
|
|
if (encoding == null) {
|
|
encoding = 'utf8';
|
|
}
|
|
}
|
|
if ((_ref4 = encoding.toLowerCase()) !== 'ascii' && _ref4 !== 'utf8' && _ref4 !== 'utf-8') {
|
|
if (Iconv != null) {
|
|
this.log('info', "Converting encoding " + encoding + " to UTF-8 on " + fullPath);
|
|
try {
|
|
buffer = new Iconv(encoding, 'utf8').convert(buffer);
|
|
} catch (_error) {
|
|
err = _error;
|
|
this.log('warn', "Encoding conversion failed, therefore we cannot convert the encoding " + encoding + " to UTF-8 on " + fullPath);
|
|
}
|
|
} else {
|
|
this.log('warn', "Iconv did not load, therefore we cannot convert the encoding " + encoding + " to UTF-8 on " + fullPath);
|
|
}
|
|
}
|
|
changes.encoding = encoding;
|
|
} else {
|
|
encoding = 'binary';
|
|
changes.encoding = encoding;
|
|
}
|
|
}
|
|
if (encoding === 'binary') {
|
|
content = source = '';
|
|
changes.content = content;
|
|
changes.source = source;
|
|
} else {
|
|
source = buffer.toString('utf8');
|
|
content = source;
|
|
changes.content = content;
|
|
changes.source = source;
|
|
}
|
|
this.set(changes);
|
|
next();
|
|
return this;
|
|
};
|
|
|
|
FileModel.prototype.normalize = function(opts, next) {
|
|
var basename, changes, contentType, date, err, extension, extensions, filename, fullDirPath, fullPath, meta, mtime, name, outBasename, outContentType, outDirPath, outExtension, outFilename, outPath, relativeBase, relativeDirPath, relativeOutBase, relativeOutDirPath, relativeOutPath, relativePath, slug, url, _defaultUrl, _ref2;
|
|
if (opts == null) {
|
|
opts = {};
|
|
}
|
|
_ref2 = extractOptsAndCallback(opts, next), opts = _ref2[0], next = _ref2[1];
|
|
changes = {};
|
|
meta = this.getMeta();
|
|
filename = opts.filename || this.get('filename') || null;
|
|
relativePath = opts.relativePath || this.get('relativePath') || null;
|
|
fullPath = opts.fullPath || this.get('fullPath') || null;
|
|
mtime = opts.mtime || this.get('mtime') || null;
|
|
date = opts.date || meta.get('date') || null;
|
|
name = opts.name || meta.get('name') || null;
|
|
slug = opts.slug || meta.get('slug') || null;
|
|
url = opts.url || meta.get('url') || null;
|
|
contentType = opts.contentType || meta.get('contentType') || null;
|
|
outContentType = opts.outContentType || meta.get('outContentType') || null;
|
|
outFilename = opts.outFilename || meta.get('outFilename') || null;
|
|
outExtension = opts.outExtension || meta.get('outExtension') || null;
|
|
outPath = opts.outPath || meta.get('outPath') || null;
|
|
extensions = null;
|
|
extension = null;
|
|
basename = null;
|
|
outBasename = null;
|
|
relativeOutPath = null;
|
|
relativeDirPath = null;
|
|
relativeOutDirPath = null;
|
|
relativeBase = null;
|
|
relativeOutBase = null;
|
|
outDirPath = null;
|
|
fullDirPath = null;
|
|
changes.filename = filename = this.getFilename({
|
|
filename: filename,
|
|
relativePath: relativePath,
|
|
fullPath: fullPath
|
|
});
|
|
if (!filename) {
|
|
err = new Error('filename is required, it can be specified via filename, fullPath, or relativePath');
|
|
return next(err);
|
|
}
|
|
if (!relativePath && filename) {
|
|
changes.relativePath = relativePath = filename;
|
|
}
|
|
changes.basename = basename = docpadUtil.getBasename(filename);
|
|
changes.extensions = extensions = this.getExtensions({
|
|
filename: filename
|
|
});
|
|
changes.extension = extension = docpadUtil.getExtension(extensions);
|
|
if (fullPath) {
|
|
changes.fullDirPath = fullDirPath = docpadUtil.getDirPath(fullPath);
|
|
}
|
|
changes.relativeDirPath = relativeDirPath = docpadUtil.getDirPath(relativePath);
|
|
changes.relativeBase = relativeBase = relativeDirPath ? pathUtil.join(relativeDirPath, basename) : basename;
|
|
if (!contentType) {
|
|
changes.contentType = contentType = mime.lookup(fullPath || relativePath);
|
|
}
|
|
if (!date) {
|
|
changes.date = date = mtime || this.get('date') || new Date();
|
|
}
|
|
if (!outFilename && !outPath) {
|
|
changes.outFilename = outFilename = docpadUtil.getOutFilename(basename, outExtension || extensions.join('.'));
|
|
}
|
|
if (!outPath) {
|
|
changes.outPath = outPath = pathUtil.resolve(this.outDirPath, relativeDirPath, outFilename);
|
|
}
|
|
changes.outDirPath = outDirPath = docpadUtil.getDirPath(outPath);
|
|
changes.outFilename = outFilename = docpadUtil.getFilename(outPath);
|
|
changes.outBasename = outBasename = docpadUtil.getBasename(outFilename);
|
|
changes.outExtension = outExtension = docpadUtil.getExtension(outFilename);
|
|
changes.relativeOutPath = relativeOutPath = outPath.replace(this.outDirPath, '').replace(/^[\/\\]/, '');
|
|
changes.relativeOutDirPath = relativeOutDirPath = docpadUtil.getDirPath(relativeOutPath);
|
|
changes.relativeOutBase = relativeOutBase = pathUtil.join(relativeOutDirPath, outBasename);
|
|
if (!name) {
|
|
changes.name = name = outFilename;
|
|
}
|
|
_defaultUrl = docpadUtil.getUrl(relativeOutPath);
|
|
if (url) {
|
|
this.setUrl(url);
|
|
this.addUrl(_defaultUrl);
|
|
} else {
|
|
this.setUrl(_defaultUrl);
|
|
}
|
|
if (!outContentType && contentType) {
|
|
changes.outContentType = outContentType = mime.lookup(outPath || relativeOutPath) || contentType;
|
|
}
|
|
if (!slug) {
|
|
changes.slug = slug = docpadUtil.getSlug(relativeOutBase);
|
|
}
|
|
this.set(changes);
|
|
next();
|
|
return this;
|
|
};
|
|
|
|
FileModel.prototype.contextualize = function(opts, next) {
|
|
var _ref2;
|
|
if (opts == null) {
|
|
opts = {};
|
|
}
|
|
_ref2 = extractOptsAndCallback(opts, next), opts = _ref2[0], next = _ref2[1];
|
|
next();
|
|
return this;
|
|
};
|
|
|
|
FileModel.prototype.write = function(opts, next) {
|
|
var err, file, _ref2, _ref3;
|
|
_ref2 = extractOptsAndCallback(opts, next), opts = _ref2[0], next = _ref2[1];
|
|
file = this;
|
|
opts.path || (opts.path = this.get('outPath'));
|
|
opts.encoding || (opts.encoding = this.get('encoding'));
|
|
opts.content || (opts.content = this.getContent());
|
|
opts.type || (opts.type = 'file');
|
|
if (!opts.path) {
|
|
next();
|
|
return this;
|
|
}
|
|
if ((_ref3 = opts.encoding.toLowerCase()) !== 'ascii' && _ref3 !== 'utf8' && _ref3 !== 'utf-8' && _ref3 !== 'binary') {
|
|
if (Iconv != null) {
|
|
this.log('info', "Converting encoding UTF-8 to " + opts.encoding + " on " + opts.path);
|
|
try {
|
|
opts.content = new Iconv('utf8', opts.encoding).convert(opts.content);
|
|
} catch (_error) {
|
|
err = _error;
|
|
this.log('warn', "Encoding conversion failed, therefore we cannot convert the encoding UTF-8 to " + opts.encoding + " on " + opts.path);
|
|
}
|
|
} else {
|
|
this.log('warn', "Iconv did not load, therefore we cannot convert the encoding UTF-8 to " + opts.encoding + " on " + opts.path);
|
|
}
|
|
}
|
|
file.log('debug', "Writing the " + opts.type + ": " + opts.path + " " + opts.encoding);
|
|
safefs.writeFile(opts.path, opts.content, function(err) {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
file.log('debug', "Wrote the " + opts.type + ": " + opts.path + " " + opts.encoding);
|
|
return next();
|
|
});
|
|
return this;
|
|
};
|
|
|
|
FileModel.prototype["delete"] = function(next) {
|
|
var file, fileOutPath;
|
|
file = this;
|
|
fileOutPath = this.get('outPath');
|
|
if (!fileOutPath) {
|
|
next();
|
|
return this;
|
|
}
|
|
file.log('debug', "Delete the file: " + fileOutPath);
|
|
safefs.exists(fileOutPath, function(exists) {
|
|
if (!exists) {
|
|
return next();
|
|
}
|
|
return safefs.unlink(fileOutPath, function(err) {
|
|
if (err) {
|
|
return next(err);
|
|
}
|
|
file.log('debug', "Deleted the file: " + fileOutPath);
|
|
return next();
|
|
});
|
|
});
|
|
return this;
|
|
};
|
|
|
|
return FileModel;
|
|
|
|
})(Model);
|
|
|
|
module.exports = FileModel;
|