Skip to content

Commit 93a0547

Browse files
authored
Merge pull request #151 from simplabs/no-debug
Adding the `no-debug` rule
2 parents 4722132 + 65c47bb commit 93a0547

File tree

4 files changed

+239
-0
lines changed

4 files changed

+239
-0
lines changed

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ module.exports = {
55
'no-native-promise-helpers': require('./rules/no-native-promise-helpers'),
66
'no-perform-without-catch': require('./rules/no-perform-without-catch'),
77
'require-task-name-suffix': require('./rules/require-task-name-suffix'),
8+
'no-debug': require('./rules/no-debug'),
89
},
910
};

rules/no-debug.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
'use strict';
2+
3+
const { hasTaskDecorator } = require('../utils/utils');
4+
5+
module.exports = {
6+
create(context) {
7+
return {
8+
Property(node) {
9+
if (node.method || node.shorthand || node.computed) return;
10+
let { key, value } = node;
11+
if (hasTaskCallExpression(value) && hasDebugCallee(value)) {
12+
context.report({
13+
node: key,
14+
message: 'Unexpected task debugger',
15+
});
16+
}
17+
},
18+
MethodDefinition(node) {
19+
let { key, value, decorators } = node;
20+
if (!decorators) return;
21+
if (!value) return;
22+
if (!value.generator) return;
23+
if (hasTaskDecorator(node) && hasDebugArgument(node)) {
24+
context.report({
25+
node: key,
26+
message: 'Unexpected task debugger',
27+
});
28+
}
29+
},
30+
ClassProperty(node) {
31+
if (node.static || node.computed) return;
32+
33+
let { key, value, decorators } = node;
34+
if (value !== null) return;
35+
if (!decorators) return;
36+
37+
for (let decorator of node.decorators) {
38+
if (hasTaskCallExpression(decorator.expression) && hasDebugCallee(decorator.expression)) {
39+
context.report({
40+
node: key,
41+
message: 'Unexpected task debugger',
42+
});
43+
}
44+
}
45+
},
46+
};
47+
},
48+
};
49+
50+
function hasTaskCallExpression(node) {
51+
return Boolean(findTaskCallExpression(node));
52+
}
53+
54+
function findTaskCallExpression(node) {
55+
if (isTaskCallExpression(node)) {
56+
return node;
57+
}
58+
59+
if (node.type === 'CallExpression' && node.callee.type === 'MemberExpression') {
60+
return findTaskCallExpression(node.callee.object);
61+
}
62+
}
63+
64+
function isTaskCallExpression(node) {
65+
return (
66+
node.type === 'CallExpression' &&
67+
node.callee.type === 'Identifier' &&
68+
node.callee.name === 'task' &&
69+
node.arguments[0] &&
70+
node.arguments[0].type === 'FunctionExpression' &&
71+
node.arguments[0].generator
72+
);
73+
}
74+
75+
function hasDebugCallee(node) {
76+
let { callee } = node;
77+
return (
78+
callee.type === 'MemberExpression' &&
79+
callee.property &&
80+
callee.property.type === 'Identifier' &&
81+
callee.property.name === 'debug'
82+
);
83+
}
84+
85+
function hasDebugArgument(node) {
86+
if (!node.decorators) return false;
87+
88+
return node.decorators.some(decorator => {
89+
let { expression } = decorator;
90+
91+
if (!expression) return false;
92+
if (!expression.arguments) return false;
93+
94+
return expression.arguments.some(argument => {
95+
if (argument.type !== 'ObjectExpression') return false;
96+
97+
return argument.properties.some(property => {
98+
return property.key && property.key.name === 'debug';
99+
});
100+
});
101+
});
102+
}

rules/no-debug.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# no-debug
2+
3+
This rule ensures that all `ember-concurrency` tasks in the app
4+
do not have debug shipped into production.
5+
6+
7+
## Examples
8+
9+
This rule **forbids** the following:
10+
11+
```js
12+
export default Component.extend({
13+
submit: task(function*() {
14+
//...
15+
}).debug(),
16+
})
17+
```
18+
19+
```js
20+
export default class extends Component {
21+
@(task(function*() {
22+
//...
23+
}).debug()) submitTask;
24+
}
25+
```
26+
27+
```js
28+
export default class extends Component {
29+
@task({ debug: true }) *submitTask() {
30+
//...
31+
}
32+
}
33+
34+
```
35+
36+
This rule **allows** the following:
37+
38+
```js
39+
export default class extends Component {
40+
@task *submitTask() { };
41+
}
42+
```
43+
44+
```js
45+
export default Component.extend({
46+
submit: task(function*() {
47+
//...
48+
}).debug(),
49+
})
50+
```
51+
52+
```js
53+
export default class extends Component {
54+
@(task(function*() {
55+
//...
56+
}).debug()) submitTask;
57+
}
58+
```

rules/no-debug.test.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
const { RuleTester } = require('eslint');
2+
3+
const rule = require('./no-debug');
4+
5+
let VALID = [`export default Component.extend({ submitTask: task(function*() {}) });`];
6+
7+
let INVALID = [
8+
{
9+
code: `export default Component.extend({ submitTask: task(function*() {}).debug() });`,
10+
errors: [{ message: 'Unexpected task debugger', column: 35 }],
11+
},
12+
];
13+
14+
let VALID_BABEL = [
15+
`export default class extends Component { @task *submitTask() { }; }`,
16+
`export default class extends Component { @restartableTask *submitTask() { }; }`,
17+
`export default class extends Component { @dropTask *submitTask() { }; }`,
18+
`export default class extends Component { @keepLatestTask *submitTask() { }; }`,
19+
`export default class extends Component { @enqueueTask *submitTask() { }; }`,
20+
`export default class extends Component { @task(function*() {}) submitTask; }`,
21+
`export default class extends Component { @(task(function*() {})) submitTask; }`,
22+
];
23+
24+
let INVALID_BABEL = [
25+
{
26+
code: `export default class extends Component { @(task(function*() {}).debug()) submitTask; }`,
27+
errors: [{ message: 'Unexpected task debugger', column: 74 }],
28+
},
29+
{
30+
code: `export default class extends Component { @(task(function*() {}).debug()) submitTask; }`,
31+
errors: [{ message: 'Unexpected task debugger', column: 74 }],
32+
},
33+
{
34+
code: `export default class extends Component { @task({ debug: true }) *submitTask() { } }`,
35+
errors: [{ message: 'Unexpected task debugger', column: 66 }],
36+
},
37+
{
38+
code: `export default class extends Component { @restartableTask({ debug: true }) *submitTask() { } }`,
39+
errors: [{ message: 'Unexpected task debugger', column: 77 }],
40+
},
41+
{
42+
code: `export default class extends Component { @dropTask({ debug: true }) *submitTask() { } }`,
43+
errors: [{ message: 'Unexpected task debugger', column: 70 }],
44+
},
45+
{
46+
code: `export default class extends Component { @keepLatestTask({ debug: true }) *submitTask() { } }`,
47+
errors: [{ message: 'Unexpected task debugger', column: 76 }],
48+
},
49+
{
50+
code: `export default class extends Component { @enqueueTask({ debug: true }) *submitTask() { } }`,
51+
errors: [{ message: 'Unexpected task debugger', column: 73 }],
52+
},
53+
];
54+
55+
let ruleTester = new RuleTester({
56+
parserOptions: {
57+
ecmaVersion: 2018,
58+
sourceType: 'module',
59+
},
60+
});
61+
62+
ruleTester.run('no-debug', rule, {
63+
valid: VALID,
64+
invalid: INVALID,
65+
});
66+
67+
let babelRuleTester = new RuleTester({
68+
parser: require.resolve('babel-eslint'),
69+
parserOptions: {
70+
ecmaVersion: 2018,
71+
sourceType: 'module',
72+
},
73+
});
74+
75+
babelRuleTester.run('no-debug', rule, {
76+
valid: [...VALID, ...VALID_BABEL],
77+
invalid: [...INVALID, ...INVALID_BABEL],
78+
});

0 commit comments

Comments
 (0)