bifocal/node_modules/gscan/lib/checks/110-page-builder-usage.js

182 lines
5.7 KiB
JavaScript

const _ = require('lodash');
const spec = require('../specs');
const {versions} = require('../utils');
const ASTLinter = require('../ast-linter');
function getRules(id, options) {
const checkVersion = _.get(options, 'checkVersion', versions.default);
let ruleSet = spec.get([checkVersion]);
const ruleRegex = new RegExp('^' + id + '-.*', 'g');
ruleSet = _.pickBy(ruleSet.rules, function (rule, ruleCode) {
if (ruleCode.match(ruleRegex)) {
return rule;
}
});
return ruleSet;
}
function getLogger({theme, rule, file = null}) {
return {
failure: (content) => {
if (!theme.results.fail[rule.code]) {
theme.results.fail[rule.code] = {failures: []};
}
const failure = {
...content,
rule: rule.code
};
if (file) {
failure.ref = file.file;
}
theme.results.fail[rule.code].failures.push(failure);
}
};
}
function applyRule(rule, theme) {
// The result variable is passed around to keep a state through the full lifecycle
const result = {};
try {
// Check if the rule is enabled (optional)
if (typeof rule.isEnabled === 'function') {
if (!rule.isEnabled({theme, log: getLogger({theme, rule}), result, options: rule.options})) {
return;
}
} else if (typeof rule.isEnabled === 'boolean' && !rule.isEnabled) {
return;
}
// Initialize the rule (optional)
if (typeof rule.init === 'function') {
rule.init({theme, log: getLogger({theme, rule}), result});
}
// Run the main function on each theme file (optional)
if (typeof rule.eachFile === 'function') {
_.each(theme.files, function (themeFile) {
rule.eachFile({file: themeFile, theme, log: getLogger({theme, rule}), result});
});
}
// Run the final function
if (typeof rule.done === 'function') {
rule.done({theme, log: getLogger({theme, rule}), result});
}
} catch (e) {
// Output something instead of failing silently (should never happen)
// eslint-disable-next-line
console.error('gscan failure', e);
}
}
function parseWithAST({theme, log, file, rules, callback}) {
const linter = new ASTLinter();
// // This rule is needed to find partials
// // Partials are needed for a full parsing
if (!rules['mark-used-partials']) {
rules['mark-used-partials'] = require(`../ast-linter/rules/mark-used-partials`);
}
function processFile(themeFile) {
if (themeFile.parsed.error) {
// Ignore parsing errors, they are handled in 005
return;
}
const astResults = linter.verify({
parsed: themeFile.parsed,
rules,
source: themeFile.content,
moduleId: themeFile.file
});
if (astResults.length) {
log.failure({
message: astResults[0].message,
ref: themeFile.file
});
}
if (typeof callback === 'function') {
callback(linter);
}
linter.partials.forEach(({normalizedName}) => {
const partialFile = theme.files.find(f => f.normalizedFile === `partials/${normalizedName}.hbs`);
if (partialFile) {
processFile(partialFile);
}
});
}
return processFile(file);
}
const ruleImplementations = {
'GS110-NO-MISSING-PAGE-BUILDER-USAGE': {
isEnabled: true,
init: ({result}) => {
result.pageBuilderProperties = new Set();
},
eachFile: ({file, theme, log, result}) => {
const templateTest = file.file.match(/(?<!partials\/.+?)\.hbs$/);
if (templateTest) {
parseWithAST({file, theme, rules: {
'mark-used-page-properties': require(`../ast-linter/rules/mark-used-page-properties`)
}, log, callback: (linter) => {
linter.usedPageProperties.forEach((variable) => {
result.pageBuilderProperties.add(variable);
});
}});
}
},
done: ({log, result}) => {
// TODO: get this from the spec rather than hard-coding to account for version changes
const knownPageBuilderProperties = ['show_title_and_feature_image'];
const notUsedProperties = knownPageBuilderProperties.filter(x => !result.pageBuilderProperties.has(x));
notUsedProperties.forEach((property) => {
log.failure({
ref: `page.hbs`,
message: `@page.${property} is not used`
});
});
}
},
'GS110-NO-UNKNOWN-PAGE-BUILDER-USAGE': {
isEnabled: true,
eachFile: ({file, theme, log}) => {
const templateTest = file.file.match(/(?<!partials\/.+?)\.hbs$/);
if (templateTest) {
parseWithAST({
file, theme, rules: {
'no-unknown-page-properties': require(`../ast-linter/rules/lint-no-unknown-page-properties`)
}, log, callback: () => {}
});
}
}
}
};
function checkUsage(theme, options) {
const rules = getRules('GS110', options);
_.each(rules, function (check, ruleCode) {
applyRule({
code: ruleCode,
...check,
...ruleImplementations[ruleCode],
options
}, theme);
});
return theme;
}
module.exports = checkUsage;