mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
@@ -67,6 +67,7 @@ Finally, enable all of the rules that you would like to use.
|
||||
"meteor/no-session": 2,
|
||||
"meteor/no-blaze-lifecycle-assignment": 2,
|
||||
"meteor/no-zero-timeout": 2
|
||||
"meteor/blaze-consistent-eventmap-params": 2,
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -91,6 +92,7 @@ A complete example of how to set up ESLint-plugin-Meteor in a Meteor project can
|
||||
* [no-session](docs/rules/no-session.md): Prevent usage of Session
|
||||
* [no-blaze-lifecycle-assignment](docs/rules/no-blaze-lifecycle-assignment.md): Prevent deprecated template lifecycle callback assignments
|
||||
* [no-zero-timeout](docs/rules/no-zero-timeout.md): Prevent usage of Meteor.setTimeout with zero delay
|
||||
* [blaze-consistent-eventmap-params](docs/rules/blaze-consistent-eventmap-params.md): Force consistent event handler parameters in event maps
|
||||
|
||||
## To Do
|
||||
|
||||
|
||||
83
docs/rules/blaze-consistent-eventmap-params.md
Normal file
83
docs/rules/blaze-consistent-eventmap-params.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# Consistent event handler parameters (blaze-consistent-eventmap-params)
|
||||
|
||||
Force consistent event handler parameters in [event maps](http://docs.meteor.com/#/full/eventmaps)
|
||||
|
||||
|
||||
## Rule Details
|
||||
|
||||
Prevent the use of differently named parameters in event handlers to achieve more consistent code
|
||||
|
||||
The following patterns are considered warnings:
|
||||
|
||||
```js
|
||||
// all on the client
|
||||
Template.foo.events({
|
||||
// 'foo' does not match 'event'
|
||||
'submit form': function (foo) {}
|
||||
})
|
||||
|
||||
Template.foo.events({
|
||||
// 'bar' does not match 'templateInstance'
|
||||
'submit form': function (event, bar) {}
|
||||
})
|
||||
|
||||
Template.foo.events({
|
||||
// neither 'foo' nor 'bar' are correct
|
||||
'submit form': function (foo, bar) {}
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
The following patterns are not warnings:
|
||||
|
||||
```js
|
||||
// on the client
|
||||
Template.foo.events({
|
||||
'submit form': function (event) {}
|
||||
})
|
||||
|
||||
// on the client
|
||||
Template.foo.events({
|
||||
'submit form': function (event, templateInstance) {}
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
You can optionally set the names of the parameters.
|
||||
You can set the name of the event parameter using `eventParamName` and the name of the template-instance parameterusing `templateInstanceParamName`.
|
||||
Here are examples of how to do this:
|
||||
|
||||
```js
|
||||
/*
|
||||
eslint meteor/blaze-consistent-eventmap-params: [2, {"eventParamName": "evt"}]
|
||||
*/
|
||||
Template.foo.events({
|
||||
'submit form': function (evt) {}
|
||||
})
|
||||
|
||||
/*
|
||||
eslint meteor/blaze-consistent-eventmap-params: [2, {"templateInstanceParamName": "tmplInst"}]
|
||||
*/
|
||||
Template.foo.events({
|
||||
'submit form': function (event, tmplInst) {}
|
||||
})
|
||||
|
||||
/*
|
||||
eslint meteor/blaze-consistent-eventmap-params: [2, {"eventParamName": "evt", "templateInstanceParamName": "tmplInst"}]
|
||||
*/
|
||||
Template.foo.events({
|
||||
'submit form': function (evt, tmplInst) {}
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
Checks client-side only.
|
||||
If you use an event map in a universal file (server and client) then the `Meteor.isClient` checks must happen in `if`-conditions with exactly one condition.
|
||||
|
||||
## Further Reading
|
||||
|
||||
* http://docs.meteor.com/#/full/eventmaps
|
||||
@@ -28,7 +28,8 @@ module.exports = {
|
||||
'audit-argument-checks': unpack('./rules/audit-argument-checks'),
|
||||
'no-session': unpack('./rules/no-session'),
|
||||
'no-blaze-lifecycle-assignment': unpack('./rules/no-blaze-lifecycle-assignment'),
|
||||
'no-zero-timeout': unpack('./rules/no-zero-timeout')
|
||||
'no-zero-timeout': unpack('./rules/no-zero-timeout'),
|
||||
'blaze-consistent-eventmap-params': unpack('./rules/blaze-consistent-eventmap-params')
|
||||
},
|
||||
rulesConfig: {
|
||||
|
||||
@@ -46,6 +47,7 @@ module.exports = {
|
||||
'audit-argument-checks': 0,
|
||||
'no-session': 0,
|
||||
'no-blaze-lifecycle-assignment': 0,
|
||||
'no-zero-timeout': 0
|
||||
'no-zero-timeout': 0,
|
||||
'blaze-consistent-eventmap-params': 0
|
||||
}
|
||||
}
|
||||
|
||||
93
lib/rules/blaze-consistent-eventmap-params.js
Normal file
93
lib/rules/blaze-consistent-eventmap-params.js
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @fileoverview Ensures consistent parameter names in blaze event maps
|
||||
* @author Philipp Sporrer, Dominik Ferber
|
||||
* @copyright 2015 Philipp Sporrer. All rights reserved.
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
|
||||
import {isFunction, isTemplateProp} from '../util/ast'
|
||||
import {getExecutors} from '../util'
|
||||
import {NON_METEOR} from '../util/environment'
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
module.exports = getMeta => context => {
|
||||
|
||||
const {env} = getMeta(context)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function ensureParamName (param, expectedParamName) {
|
||||
if (param && param.name !== expectedParamName) {
|
||||
context.report(
|
||||
param,
|
||||
`Invalid parameter name, use "${expectedParamName}" instead`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function validateEventDef (eventDefNode) {
|
||||
|
||||
const eventHandler = eventDefNode.value
|
||||
if (isFunction(eventHandler.type)) {
|
||||
|
||||
ensureParamName(
|
||||
eventHandler.params[0],
|
||||
context.options[0] ? context.options[0].eventParamName : 'event'
|
||||
)
|
||||
|
||||
ensureParamName(
|
||||
eventHandler.params[1],
|
||||
context.options[0] ? context.options[0].templateInstanceParamName : 'templateInstance'
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
if (env === NON_METEOR) {
|
||||
return {}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
CallExpression: function (node) {
|
||||
|
||||
if (node.arguments.length === 0 || !isTemplateProp(node.callee, 'events')) {
|
||||
return
|
||||
}
|
||||
const executors = getExecutors(env, context.getAncestors())
|
||||
if (executors.has('browser') || executors.has('cordova')) {
|
||||
const eventMap = node.arguments[0]
|
||||
|
||||
if (eventMap.type === 'ObjectExpression') {
|
||||
eventMap.properties.forEach((eventDef) => validateEventDef(eventDef))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports.schema = [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
eventParamName: {
|
||||
type: 'string'
|
||||
},
|
||||
templateInstanceParamName: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
@@ -1,5 +1,6 @@
|
||||
export {default as isMeteorCall} from './isMeteorCall'
|
||||
export {default as isMeteorProp} from './isMeteorProp'
|
||||
export {default as isTemplateProp} from './isTemplateProp'
|
||||
export {default as isFunction} from './isFunction'
|
||||
export {default as getPropertyName} from './getPropertyName'
|
||||
export {default as areRefsTrackable} from './areRefsTrackable'
|
||||
|
||||
10
lib/util/ast/isTemplateProp.js
Normal file
10
lib/util/ast/isTemplateProp.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import getPropertyName from './getPropertyName'
|
||||
|
||||
export default function (node, propName) {
|
||||
return (
|
||||
node.type === 'MemberExpression' &&
|
||||
node.object.type === 'MemberExpression' &&
|
||||
node.object.object.type === 'Identifier' && node.object.object.name === 'Template' &&
|
||||
getPropertyName(node.property) === propName
|
||||
)
|
||||
}
|
||||
253
tests/lib/rules/blaze-consistent-eventmap-params.js
Normal file
253
tests/lib/rules/blaze-consistent-eventmap-params.js
Normal file
@@ -0,0 +1,253 @@
|
||||
/**
|
||||
* @fileoverview Ensures that the names of the arguments of event handlers are always the same
|
||||
* @author Philipp Sporrer, Dominik Ferber
|
||||
* @copyright 2015 Philipp Sporrer. All rights reserved.
|
||||
* See LICENSE file in root directory for full license.
|
||||
*/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Requirements
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
import {
|
||||
CLIENT,
|
||||
UNIVERSAL,
|
||||
NON_METEOR
|
||||
} from '../../../dist/util/environment.js'
|
||||
const rule = require('../../../dist/rules/blaze-consistent-eventmap-params')
|
||||
const RuleTester = require('eslint').RuleTester
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Tests
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const ruleTester = new RuleTester()
|
||||
ruleTester.run('blaze-consistent-eventmap-params', rule(() => ({env: CLIENT})), {
|
||||
|
||||
valid: [
|
||||
`
|
||||
Foo.bar.events({
|
||||
'submit form': function (bar, baz) {
|
||||
// no error, because not on Template
|
||||
}
|
||||
})
|
||||
`,
|
||||
`
|
||||
Template.foo.events({
|
||||
'submit form': function (event) {}
|
||||
})
|
||||
`,
|
||||
`
|
||||
Template['foo'].events({
|
||||
'submit form': function (event) {}
|
||||
})
|
||||
`,
|
||||
`
|
||||
Template['foo']['events']({
|
||||
'submit form': function (event) {}
|
||||
})
|
||||
`,
|
||||
`
|
||||
Template.foo['events']({
|
||||
'submit form': function (event) {}
|
||||
})
|
||||
`,
|
||||
`
|
||||
Template.foo.events({
|
||||
'submit form': {}
|
||||
})
|
||||
`,
|
||||
`
|
||||
Template.foo.events()
|
||||
`,
|
||||
`
|
||||
Template.foo.events(null)
|
||||
`,
|
||||
{
|
||||
code: `
|
||||
Template.foo.events({
|
||||
'submit form': function (evt) {}
|
||||
})
|
||||
`,
|
||||
options: [{
|
||||
eventParamName: 'evt'
|
||||
}]
|
||||
},
|
||||
{
|
||||
code: `
|
||||
Template.foo.events({
|
||||
'submit form': function (evt, tmplInst) {}
|
||||
})
|
||||
`,
|
||||
options: [{
|
||||
eventParamName: 'evt',
|
||||
templateInstanceParamName: 'tmplInst'
|
||||
}]
|
||||
},
|
||||
`
|
||||
Template.foo.events({
|
||||
'submit form': function (event, templateInstance) {}
|
||||
})
|
||||
`,
|
||||
{
|
||||
code: `
|
||||
Template.foo.events({
|
||||
'submit form': (event, templateInstance) => {}
|
||||
})
|
||||
`,
|
||||
parser: 'babel-eslint'
|
||||
}
|
||||
],
|
||||
|
||||
invalid: [
|
||||
{
|
||||
code: `
|
||||
Template.foo.events({
|
||||
'submit form': function (foo, bar) {}
|
||||
})
|
||||
`,
|
||||
errors: [
|
||||
{message: 'Invalid parameter name, use "event" instead', type: 'Identifier'},
|
||||
{message: 'Invalid parameter name, use "templateInstance" instead', type: 'Identifier'}
|
||||
]
|
||||
},
|
||||
{
|
||||
code: `
|
||||
Template['foo'].events({
|
||||
'submit form': function (foo, bar) {}
|
||||
})
|
||||
`,
|
||||
errors: [
|
||||
{message: 'Invalid parameter name, use "event" instead', type: 'Identifier'},
|
||||
{message: 'Invalid parameter name, use "templateInstance" instead', type: 'Identifier'}
|
||||
]
|
||||
},
|
||||
{
|
||||
code: `
|
||||
Template['foo']['events']({
|
||||
'submit form': function (foo, bar) {}
|
||||
})
|
||||
`,
|
||||
errors: [
|
||||
{message: 'Invalid parameter name, use "event" instead', type: 'Identifier'},
|
||||
{message: 'Invalid parameter name, use "templateInstance" instead', type: 'Identifier'}
|
||||
]
|
||||
},
|
||||
{
|
||||
code: `
|
||||
Template.foo['events']({
|
||||
'submit form': function (foo, bar) {}
|
||||
})
|
||||
`,
|
||||
errors: [
|
||||
{message: 'Invalid parameter name, use "event" instead', type: 'Identifier'},
|
||||
{message: 'Invalid parameter name, use "templateInstance" instead', type: 'Identifier'}
|
||||
]
|
||||
},
|
||||
{
|
||||
code: `
|
||||
Template.foo.events({
|
||||
'submit form': (foo, bar) => {}
|
||||
})
|
||||
`,
|
||||
errors: [
|
||||
{message: 'Invalid parameter name, use "event" instead', type: 'Identifier'},
|
||||
{message: 'Invalid parameter name, use "templateInstance" instead', type: 'Identifier'}
|
||||
],
|
||||
parser: 'babel-eslint'
|
||||
},
|
||||
{
|
||||
code: `
|
||||
Template.foo.events({
|
||||
'submit form': function (foo, templateInstance) {}
|
||||
})
|
||||
`,
|
||||
errors: [
|
||||
{message: 'Invalid parameter name, use "event" instead', type: 'Identifier'}
|
||||
]
|
||||
},
|
||||
{
|
||||
code: `
|
||||
Template.foo.events({
|
||||
'submit form': function (event, bar) {}
|
||||
})
|
||||
`,
|
||||
errors: [
|
||||
{message: 'Invalid parameter name, use "templateInstance" instead', type: 'Identifier'}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
})
|
||||
|
||||
ruleTester.run('blaze-consistent-eventmap-params', rule(() => ({env: UNIVERSAL})), {
|
||||
|
||||
valid: [
|
||||
`
|
||||
Nontemplate.foo.events({
|
||||
'submit form': function (bar, baz) {
|
||||
// no error, because not on Template
|
||||
}
|
||||
})
|
||||
`,
|
||||
`
|
||||
if (Meteor.isCordova) {
|
||||
Template.foo.events({
|
||||
'submit form': function (event, templateInstance) {}
|
||||
})
|
||||
}
|
||||
`,
|
||||
`
|
||||
if (Meteor.isServer) {
|
||||
Template.foo.events({
|
||||
'submit form': function (bar, baz) {}
|
||||
})
|
||||
}
|
||||
`,
|
||||
`
|
||||
if (Meteor.isClient) {
|
||||
Template.foo.events({
|
||||
'submit form': function (event, templateInstance) {}
|
||||
})
|
||||
}
|
||||
`,
|
||||
{
|
||||
code: `
|
||||
if (Meteor.isClient) {
|
||||
Template.foo.events({
|
||||
'submit form': (event, templateInstance) => {}
|
||||
})
|
||||
}
|
||||
`,
|
||||
parser: 'babel-eslint'
|
||||
}
|
||||
],
|
||||
|
||||
invalid: [
|
||||
{
|
||||
code: `
|
||||
if (Meteor.isClient) {
|
||||
Template.foo.events({
|
||||
'submit form': function (foo, bar) {}
|
||||
})
|
||||
}
|
||||
`,
|
||||
errors: [
|
||||
{message: 'Invalid parameter name, use "event" instead', type: 'Identifier'},
|
||||
{message: 'Invalid parameter name, use "templateInstance" instead', type: 'Identifier'}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
})
|
||||
|
||||
ruleTester.run('blaze-consistent-eventmap-params', rule(() => ({env: NON_METEOR})), {
|
||||
valid: [
|
||||
`
|
||||
Template.foo.events({
|
||||
'submit form': function (foo, bar) {}
|
||||
})
|
||||
`
|
||||
],
|
||||
invalid: []
|
||||
})
|
||||
Reference in New Issue
Block a user