Skip to content
This repository has been archived by the owner on Oct 2, 2021. It is now read-only.

Commit

Permalink
feat(blaze-consistent-eventmap-params): Add rule
Browse files Browse the repository at this point in the history
closes #12, #33
  • Loading branch information
dferber90 committed Oct 28, 2015
1 parent 7d428c4 commit be73ffa
Show file tree
Hide file tree
Showing 7 changed files with 446 additions and 2 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
```
Expand All @@ -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

Expand Down
83 changes: 83 additions & 0 deletions docs/rules/blaze-consistent-eventmap-params.md
Original file line number Diff line number Diff line change
@@ -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
6 changes: 4 additions & 2 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {

Expand All @@ -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 changes: 93 additions & 0 deletions lib/rules/blaze-consistent-eventmap-params.js
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions lib/util/ast/index.js
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
10 changes: 10 additions & 0 deletions lib/util/ast/isTemplateProp.js
Original file line number Diff line number Diff line change
@@ -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
)
}
Loading

0 comments on commit be73ffa

Please sign in to comment.