bifocal/node_modules/gscan/lib/checker.js

123 lines
3.6 KiB
JavaScript

const _ = require('lodash');
const requireDir = require('require-dir');
const debug = require('@tryghost/debug')('checker');
const errors = require('@tryghost/errors');
const versions = require('./utils').versions;
// An object containing helpers as keys and their labs flag as values
// E.g. match: 'matchHelper'
const labsEnabledHelpers = {
};
/**
* Check theme
*
* Takes a theme path, reads the theme, and checks it for issues.
* Returns a theme object.
* @param {string} themePath
* @param {Object} options
* @param {string} [options.checkVersion] version to check the theme against
* @param {string} [options.themeName] name of the checked theme
* @param {Object=} [options.labs] object containing boolean flags for enabled labs features
* @returns {Promise<Object>}
*/
const check = async function checkAll(themePath, options = {}) {
// Require checks late to avoid loading all until used
const checks = requireDir('./checks');
const passedVersion = _.get(options, 'checkVersion', versions.default);
let version = passedVersion;
if (passedVersion === 'canary') {
version = 'v4';
options.checkVersion = 'v4';
}
_.each(labsEnabledHelpers, (flag, helper) => {
if (_.has(options.labs, flag)) {
const spec = require('./specs').get([version]);
if (!spec.knownHelpers.includes(helper)) {
spec.knownHelpers.push(helper);
}
}
});
// Require readTheme late to avoid loading entire AST parser until used
const readTheme = require('./read-theme');
try {
const theme = await readTheme(themePath);
// set the major version to check
theme.checkedVersion = versions[version].major;
const timeBeforeChecks = Date.now();
for (const checkName in checks) {
const now = Date.now();
await checks[checkName](theme, options, themePath);
debug(checkName, 'took', Date.now() - now, 'ms');
}
debug('All checks took', Date.now() - timeBeforeChecks, 'ms');
return theme;
} catch (err) {
throw new errors.ValidationError({
message: 'Failed theme files check',
help: 'Your theme file structure is corrupted or contains errors',
errorDetails: err.message,
context: options.themeName,
err
});
}
};
const checkZip = async function checkZip(path, options) {
options = Object.assign({}, {
keepExtractedDir: false
}, options);
let zip;
if (_.isString(path)) {
zip = {
path,
name: path.match(/(.*\/)?(.*).zip$/)[2]
};
} else {
zip = _.clone(path);
}
try {
const readZip = require('./read-zip');
const {path: extractedZipPath} = await readZip(zip);
const theme = await check(extractedZipPath, Object.assign({themeName: zip.name}, options));
if (options.keepExtractedDir) {
return theme;
} else {
const fs = require('fs-extra');
await fs.remove(zip.origPath);
return theme;
}
} catch (error) {
if (!errors.utils.isGhostError(error)) {
throw new errors.ValidationError({
message: 'Failed to check zip file',
help: 'Your zip file might be corrupted, try unzipping and zipping again.',
errorDetails: error.message,
context: zip.name,
err: error
});
}
throw error;
}
};
module.exports = {
check,
checkZip
};