0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-13 22:41:32 -05:00
ghost/core/server/require-tree.js
Gabor Javorszky 212711d896 Added package.js support for themes (and plugins)
Closes #2081
* Amended require-tree to populate availableThemes and availablePlugins to use full file names (`basename.ext`) as keys instead of just basename. This way `image.jpg`, `image.png`, `image.gif` won't overwrite the `image` key.
* Amended require-tree to allow package.json file parsing to return the contents of the file as json on the `package.json` key.
* settings api populates theme data `package` if it exists. Otherwise it assigns `false` to it
* `general.hbs` (salute) was reworked to if there is the package key on the theme is not false, it will use the `name` and `version` keys of that. You can break it by not having a `name` or `version` in the package.json file.
* Added error and warning messages for package.json file parse errors and misses
2014-02-13 23:57:58 +00:00

105 lines
3.8 KiB
JavaScript

var when = require('when'),
keys = require('when/keys'),
fs = require('fs'),
path = require('path'),
_ = require('lodash'),
messages = {errors: [], warns: []},
extend = function (obj, source) {
var key;
for (key in source) {
if (source.hasOwnProperty(key)) {
obj[key] = source[key];
}
}
return obj;
},
parsePackageJson = function (path) {
var packageDeferred = when.defer(),
packagePromise = packageDeferred.promise,
jsonContainer;
fs.readFile(path, function (error, data) {
if (error) {
messages.errors.push({message: 'Could not read package.json file', context: path});
packageDeferred.resolve(false);
return;
}
try {
jsonContainer = JSON.parse(data);
if (jsonContainer.hasOwnProperty('name') && jsonContainer.hasOwnProperty('version')) {
packageDeferred.resolve(jsonContainer);
} else {
messages.errors.push({message: '"name" or "version" is missing from theme package.json file.', context: path});
packageDeferred.resolve(false);
}
} catch (e) {
messages.errors.push({message: 'Theme package.json file is malformed', context: path});
packageDeferred.resolve(false);
}
});
return when(packagePromise);
},
readDir = function (dir, options, depth) {
depth = depth || 0;
options = extend({
index: true
}, options);
if (depth > 1) {
return null;
}
var subtree = {},
treeDeferred = when.defer(),
treePromise = treeDeferred.promise;
fs.readdir(dir, function (error, files) {
if (error) {
return treeDeferred.reject(error);
}
files = files || [];
files.forEach(function (file) {
var fileDeferred = when.defer(),
filePromise = fileDeferred.promise,
fpath = path.join(dir, file);
subtree[file] = filePromise;
fs.lstat(fpath, function (error, result) {
/*jslint unparam:true*/
if (result.isDirectory()) {
fileDeferred.resolve(readDir(fpath, options, depth + 1));
} else if (depth === 1 && file === "package.json") {
fileDeferred.resolve(parsePackageJson(fpath));
} else {
fileDeferred.resolve(fpath);
}
});
});
return keys.all(subtree).then(function (theFiles) {
return treeDeferred.resolve(theFiles);
});
});
return when(treePromise).then(function (prom) {
return prom;
});
},
readAll = function (dir, options, depth) {
return when(readDir(dir, options, depth)).then(function (paths) {
// for all contents of the dir, I'm interested in the ones that are directories and within /theme/
if (typeof paths === "object" && dir.indexOf('theme') !== -1) {
_.each(paths, function (path, index) {
if (typeof path === 'object' && !path.hasOwnProperty('package.json') && index.indexOf('.') !== 0) {
messages.warns.push({message: 'Theme does not have a package.json file', context: index});
}
});
}
paths._messages = messages;
return paths;
});
};
module.exports = readAll;