Skip to content

Commit 5a1af69

Browse files
authored
Merge pull request #871 from bmish/no-private-routing-service-router-main
Add `catchRouterMain` option to `no-private-routing-service` rule
2 parents 5ba1b3a + ca5611a commit 5a1af69

File tree

3 files changed

+107
-3
lines changed

3 files changed

+107
-3
lines changed

docs/rules/no-private-routing-service.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Disallow the use of:
66

77
* The private `-routing` service
88
* The private `_routerMicrolib` property (when the `catchRouterMicrolib` option is enabled)
9+
* The private `router:main` property (when the `catchRouterMain` option is enabled)
910

1011
There has been a public `router` service since Ember 2.16 and using the private routing service should be unnecessary.
1112

@@ -44,6 +45,20 @@ export default class MyComponent extends Component {
4445
}
4546
```
4647

48+
```javascript
49+
// When `catchRouterMain` option is enabled.
50+
51+
import Component from '@ember/component';
52+
import { getOwner } from '@ember/application';
53+
54+
export default class MyComponent extends Component {
55+
someFunction() {
56+
const router = getOwner(this).lookup('router:main');
57+
// ...
58+
}
59+
}
60+
```
61+
4762
Examples of **correct** code for this rule:
4863

4964
```javascript
@@ -69,6 +84,7 @@ export default class MyComponent extends Component {
6984
This rule takes an optional object containing:
7085

7186
* `boolean` -- `catchRouterMicrolib` -- whether the rule should catch usages of the private property `_routerMicrolib` (default `false`) (TODO: enable this by default in the next major release)
87+
* `boolean` -- `catchRouterMain` -- whether the rule should catch usages of the private property `router:main` (default `false`) (TODO: enable this by default in the next major release)
7288

7389
## References
7490

lib/rules/no-private-routing-service.js

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
const emberUtils = require('../utils/ember');
44
const decoratorUtils = require('../utils/decorators');
5+
const types = require('../utils/types');
56

67
//------------------------------------------------------------------------------
78
// Rule Definition
@@ -10,7 +11,11 @@ const decoratorUtils = require('../utils/decorators');
1011
const PRIVATE_ROUTING_SERVICE_ERROR_MESSAGE =
1112
"Don't inject the private '-routing' service. Instead use the public 'router' service.";
1213

13-
const ROUTER_MICROLIB_ERROR_MESSAGE = "Don't access the `_routerMicrolib` as it is private API";
14+
const ROUTER_MICROLIB_ERROR_MESSAGE =
15+
"Don't access the `_routerMicrolib` as it is a private API. Instead use the public 'router' service.";
16+
17+
const ROUTER_MAIN_ERROR_MESSAGE =
18+
"Don't access `router:main` as it is a private API. Instead use the public 'router' service.";
1419

1520
module.exports = {
1621
meta: {
@@ -31,6 +36,10 @@ module.exports = {
3136
type: 'boolean',
3237
default: false,
3338
},
39+
catchRouterMain: {
40+
type: 'boolean',
41+
default: false,
42+
},
3443
},
3544
additionalProperties: false,
3645
},
@@ -39,13 +48,15 @@ module.exports = {
3948

4049
PRIVATE_ROUTING_SERVICE_ERROR_MESSAGE,
4150
ROUTER_MICROLIB_ERROR_MESSAGE,
51+
ROUTER_MAIN_ERROR_MESSAGE,
4252

4353
create(context) {
4454
const ROUTING_SERVICE_NAME = '-routing';
4555
const ROUTER_MICROLIB_NAME = '_routerMicrolib';
4656

4757
const options = context.options[0] || {};
4858
const catchRouterMicrolib = options.catchRouterMicrolib || false;
59+
const catchRouterMain = options.catchRouterMain || false;
4960

5061
return {
5162
Property(node) {
@@ -93,6 +104,33 @@ module.exports = {
93104
context.report({ node, message: ROUTER_MICROLIB_ERROR_MESSAGE });
94105
}
95106
},
107+
108+
CallExpression(node) {
109+
checkForRouterMain(node);
110+
},
111+
112+
OptionalCallExpression(node) {
113+
checkForRouterMain(node);
114+
},
96115
};
116+
117+
function checkForRouterMain(node) {
118+
// Looks for expressions like these:
119+
// x.lookup('router:main')
120+
// x.y.lookup('router:main')
121+
// x?.lookup('router:main')
122+
if (
123+
catchRouterMain &&
124+
(types.isMemberExpression(node.callee) || types.isOptionalMemberExpression(node.callee)) &&
125+
types.isIdentifier(node.callee.property) &&
126+
node.callee.property.name === 'lookup' &&
127+
node.arguments.length === 1 &&
128+
types.isLiteral(node.arguments[0]) &&
129+
typeof node.arguments[0].value === 'string' &&
130+
node.arguments[0].value === 'router:main'
131+
) {
132+
context.report({ node, message: ROUTER_MAIN_ERROR_MESSAGE });
133+
}
134+
}
97135
},
98136
};

tests/lib/rules/no-private-routing-service.js

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
const rule = require('../../../lib/rules/no-private-routing-service');
66
const RuleTester = require('eslint').RuleTester;
77

8-
const { PRIVATE_ROUTING_SERVICE_ERROR_MESSAGE, ROUTER_MICROLIB_ERROR_MESSAGE } = rule;
8+
const {
9+
PRIVATE_ROUTING_SERVICE_ERROR_MESSAGE,
10+
ROUTER_MICROLIB_ERROR_MESSAGE,
11+
ROUTER_MAIN_ERROR_MESSAGE,
12+
} = rule;
913

1014
//------------------------------------------------------------------------------
1115
// Tests
@@ -51,9 +55,28 @@ ruleTester.run('no-private-routing-service', rule, {
5155
'class MyComponent extends Component { aProp="another value"; }',
5256
'class MyComponent extends Component { anIntProp=25; }',
5357

54-
// _routerMicrolib (`catchRouterMicrolib` option off)
58+
// _routerMicrolib
5559
"get(this, 'router._routerMicrolib');",
5660
'this.router._routerMicrolib;',
61+
{ code: "get(this, 'router.somethingElse');", options: [{ catchRouterMicrolib: true }] },
62+
{ code: 'this.router.somethingElse;', options: [{ catchRouterMicrolib: true }] },
63+
64+
// router:main
65+
"getOwner(this).lookup('router:main');",
66+
"owner.lookup('router:main');",
67+
"this.owner.lookup('router:main');",
68+
{
69+
code: "getOwner(this).lookup('router:somethingElse');",
70+
options: [{ catchRouterMicrolib: true }],
71+
},
72+
{
73+
code: "owner.lookup('router:somethingElse');",
74+
options: [{ catchRouterMicrolib: true }],
75+
},
76+
{
77+
code: "this.owner.lookup('router:somethingElse');",
78+
options: [{ catchRouterMicrolib: true }],
79+
},
5780
],
5881
invalid: [
5982
// Classic
@@ -95,5 +118,32 @@ ruleTester.run('no-private-routing-service', rule, {
95118
options: [{ catchRouterMicrolib: true }],
96119
errors: [{ message: ROUTER_MICROLIB_ERROR_MESSAGE, type: 'Identifier' }],
97120
},
121+
122+
// router:main (`catchRouterMain` option on)
123+
{
124+
code: "getOwner(this).lookup('router:main');",
125+
output: null,
126+
options: [{ catchRouterMain: true }],
127+
errors: [{ message: ROUTER_MAIN_ERROR_MESSAGE, type: 'CallExpression' }],
128+
},
129+
{
130+
code: "owner.lookup('router:main');",
131+
output: null,
132+
options: [{ catchRouterMain: true }],
133+
errors: [{ message: ROUTER_MAIN_ERROR_MESSAGE, type: 'CallExpression' }],
134+
},
135+
{
136+
code: "this.owner.lookup('router:main');",
137+
output: null,
138+
options: [{ catchRouterMain: true }],
139+
errors: [{ message: ROUTER_MAIN_ERROR_MESSAGE, type: 'CallExpression' }],
140+
},
141+
{
142+
// Optional chaining.
143+
code: "this?.owner?.lookup?.('router:main');",
144+
output: null,
145+
options: [{ catchRouterMain: true }],
146+
errors: [{ message: ROUTER_MAIN_ERROR_MESSAGE, type: 'OptionalCallExpression' }],
147+
},
98148
],
99149
});

0 commit comments

Comments
 (0)