eslint-plugin-meteor
Version:
Meteor specific linting rules for ESLint
80 lines (67 loc) • 2.51 kB
JavaScript
/**
* @fileoverview Convention for eventmap selectors
* @author Dominik Ferber
* @copyright 2016 Dominik Ferber. All rights reserved.
* See LICENSE file in root directory for full license.
*/
const { isTemplateProp } = require('../util/ast');
// -----------------------------------------------------------------------------
// Rule Definition
// -----------------------------------------------------------------------------
module.exports = {
meta: {
schema: [{ type: 'string' }, { enum: ['relaxed', 'strict'] }],
},
create: (context) => {
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
const [prefix = 'js-', mode = 'relaxed'] = context.options;
// algorithm to parse event map selector taken from blaze itself
// https://github.com/meteor/meteor/blob/15a0369581ef27a6d3d49cb0110d10b1198d5383/packages/blaze/view.js#L867
function validateEventDefinition(node) {
if (node.key.type !== 'Literal') return;
const spec = node.key.value;
const clauses = spec.split(/,\s+/);
clauses.forEach((clause) => {
const parts = clause.split(/\s+/);
if (parts.length === 1) {
if (mode === 'strict') {
context.report(node.key, 'Missing selector');
}
return;
}
const selector = parts[1];
if (selector.startsWith('.')) {
if (!selector.startsWith(`.${prefix}`)) {
context.report(
node.key,
`Expected selector to be prefixed with "${prefix}"`
);
} else if (selector === `.${prefix}`) {
context.report(node.key, 'Selector may not consist of prefix only');
}
} else if (mode === 'strict') {
context.report(node.key, 'Expected selector to be a class');
}
});
}
// ---------------------------------------------------------------------------
// Public
// ---------------------------------------------------------------------------
return {
CallExpression: (node) => {
if (
node.arguments.length === 0 ||
!isTemplateProp(node.callee, 'events')
) {
return;
}
const eventMap = node.arguments[0];
if (eventMap.type === 'ObjectExpression') {
eventMap.properties.forEach(validateEventDefinition);
}
},
};
},
};