├── .editorconfig
├── .gitignore
├── README.md
├── index.js
├── lib
└── rules
│ ├── camelcase-deprecation-support.js
│ ├── explicit-createref-type.js
│ ├── react-import-style.js
│ └── use-a11y-component.js
├── package.json
├── tests
└── lib
│ ├── index.js
│ └── rules
│ ├── camelcase-deprecation-support.js
│ ├── explicit-createref-type.js
│ ├── react-import-style.js
│ └── use-a11y-component.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # http://editorconfig.org
4 |
5 | root = true
6 |
7 | [*]
8 | indent_style = space
9 | indent_size = 2
10 | end_of_line = lf
11 | charset = utf-8
12 | max_line_length = 120
13 | trim_trailing_whitespace = true
14 | insert_final_newline = true
15 |
16 | [{*.txt,*.md,*.mkdn,*.mdown,*.markdown}]
17 | max_line_length = 0
18 | trim_trailing_whitespace = false
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | # next.js build output
61 | .next
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Usage
2 |
3 | * Use [AST Explorer](http://astexplorer.net/) to know what you're looking for
4 | * Run `yarn test` to make sure everything works
5 | * Update `index.js` to export the new rule name and any additional rules
6 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | rules: {
3 | 'react-import-style': require('./lib/rules/react-import-style'),
4 | 'use-a11y-component': require('./lib/rules/use-a11y-component'),
5 | camelcase: require('./lib/rules/camelcase-deprecation-support'),
6 | 'explicit-createref-type': require('./lib/rules/explicit-createref-type'),
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/lib/rules/camelcase-deprecation-support.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Rule to flag non-camelcased identifiers
3 | * @author Nicholas C. Zakas
4 | *
5 | * modified by Michael Greer
6 | */
7 |
8 | 'use strict';
9 |
10 | //------------------------------------------------------------------------------
11 | // Rule Definition
12 | //------------------------------------------------------------------------------
13 |
14 | module.exports = {
15 | meta: {
16 | docs: {
17 | description: 'enforce camelcase naming convention',
18 | category: 'Stylistic Issues',
19 | recommended: false,
20 | url: 'https://eslint.org/docs/rules/camelcase',
21 | },
22 |
23 | schema: [
24 | {
25 | type: 'object',
26 | properties: {
27 | properties: {
28 | enum: ['always', 'never'],
29 | },
30 | },
31 | additionalProperties: false,
32 | },
33 | ],
34 |
35 | messages: {
36 | notCamelCase: "Identifier '{{name}}' is not in camel case.",
37 | },
38 | },
39 |
40 | create(context) {
41 | //--------------------------------------------------------------------------
42 | // Helpers
43 | //--------------------------------------------------------------------------
44 |
45 | // contains reported nodes to avoid reporting twice on destructuring with shorthand notation
46 | const reported = [];
47 | const ALLOWED_PARENT_TYPES = new Set(['CallExpression', 'NewExpression']);
48 |
49 | /**
50 | * Checks if a string contains an underscore and isn't all upper-case
51 | * @param {string} name The string to check.
52 | * @returns {boolean} if the string is underscored
53 | * @private
54 | */
55 | function isUnderscored(name) {
56 | // skip UNSAFE_ beginning
57 | if (name.substring(0, 7) === 'UNSAFE_') {
58 | name = name.substring(7);
59 | }
60 | // if there's an underscore, it might be A_CONSTANT, which is okay
61 | return name.indexOf('_') > -1 && name !== name.toUpperCase();
62 | }
63 |
64 | /**
65 | * Reports an AST node as a rule violation.
66 | * @param {ASTNode} node The node to report.
67 | * @returns {void}
68 | * @private
69 | */
70 | function report(node) {
71 | if (reported.indexOf(node) < 0) {
72 | reported.push(node);
73 | context.report({node, messageId: 'notCamelCase', data: {name: node.name}});
74 | }
75 | }
76 |
77 | const options = context.options[0] || {};
78 | let properties = options.properties || '';
79 |
80 | if (properties !== 'always' && properties !== 'never') {
81 | properties = 'always';
82 | }
83 |
84 | return {
85 | Identifier(node) {
86 | /*
87 | * Leading and trailing underscores are commonly used to flag
88 | * private/protected identifiers, strip them
89 | */
90 | const name = node.name.replace(/^_+|_+$/g, ''),
91 | effectiveParent = node.parent.type === 'MemberExpression' ? node.parent.parent : node.parent;
92 |
93 | // MemberExpressions get special rules
94 | if (node.parent.type === 'MemberExpression') {
95 | // "never" check properties
96 | if (properties === 'never') {
97 | return;
98 | }
99 |
100 | // Always report underscored object names
101 | if (
102 | node.parent.object.type === 'Identifier' &&
103 | node.parent.object.name === node.name &&
104 | isUnderscored(name)
105 | ) {
106 | report(node);
107 |
108 | // Report AssignmentExpressions only if they are the left side of the assignment
109 | } else if (
110 | effectiveParent.type === 'AssignmentExpression' &&
111 | isUnderscored(name) &&
112 | (effectiveParent.right.type !== 'MemberExpression' ||
113 | (effectiveParent.left.type === 'MemberExpression' && effectiveParent.left.property.name === node.name))
114 | ) {
115 | report(node);
116 | }
117 |
118 | /*
119 | * Properties have their own rules, and
120 | * AssignmentPattern nodes can be treated like Properties:
121 | * e.g.: const { no_camelcased = false } = bar;
122 | */
123 | } else if (node.parent.type === 'Property' || node.parent.type === 'AssignmentPattern') {
124 | if (node.parent.parent && node.parent.parent.type === 'ObjectPattern') {
125 | if (node.parent.shorthand && node.parent.value.left && isUnderscored(name)) {
126 | report(node);
127 | }
128 |
129 | // prevent checking righthand side of destructured object
130 | if (node.parent.key === node && node.parent.value !== node) {
131 | return;
132 | }
133 |
134 | if (node.parent.value.name && isUnderscored(name)) {
135 | report(node);
136 | }
137 | }
138 |
139 | // "never" check properties
140 | if (properties === 'never') {
141 | return;
142 | }
143 |
144 | // don't check right hand side of AssignmentExpression to prevent duplicate warnings
145 | if (isUnderscored(name) && !ALLOWED_PARENT_TYPES.has(effectiveParent.type) && !(node.parent.right === node)) {
146 | report(node);
147 | }
148 |
149 | // Check if it's an import specifier
150 | } else if (
151 | ['ImportSpecifier', 'ImportNamespaceSpecifier', 'ImportDefaultSpecifier'].indexOf(node.parent.type) >= 0
152 | ) {
153 | // Report only if the local imported identifier is underscored
154 | if (node.parent.local && node.parent.local.name === node.name && isUnderscored(name)) {
155 | report(node);
156 | }
157 |
158 | // Report anything that is underscored that isn't a CallExpression
159 | } else if (isUnderscored(name) && !ALLOWED_PARENT_TYPES.has(effectiveParent.type)) {
160 | report(node);
161 | }
162 | },
163 | };
164 | },
165 | };
166 |
--------------------------------------------------------------------------------
/lib/rules/explicit-createref-type.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const explicitCreateRefTypeMessage = `React.createRef() class properties should be explicitly typed.`;
4 |
5 | module.exports = {
6 | meta: {
7 | messages: {
8 | explicitCreateRefTypeMessage
9 | },
10 | docs: {
11 | description: "Force explicit type annotation on class properties storing a React.createRef()",
12 | category: "Best Practices"
13 | },
14 | schema: [
15 | {
16 | type: "object",
17 | properties: {},
18 | additionalProperties: false
19 | }
20 | ]
21 | },
22 |
23 | create: function(context) {
24 | return {
25 | ClassProperty: node => {
26 | if (node.typeAnnotation) {
27 | return;
28 | }
29 |
30 | const value = node.value;
31 | if (value != null && value.type === "CallExpression") {
32 | const callee = value.callee;
33 | const typeArguments = value.typeArguments;
34 | if (
35 | callee.type === "MemberExpression" &&
36 | callee.object.name === "React" &&
37 | callee.property.name === "createRef" &&
38 | typeArguments == null
39 | ) {
40 | context.report({
41 | node,
42 | message: explicitCreateRefTypeMessage
43 | });
44 | }
45 | }
46 | }
47 | };
48 | }
49 | };
50 |
--------------------------------------------------------------------------------
/lib/rules/react-import-style.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const improperReactImport = `Import react in the following style: "import * as React from 'react';"`;
4 |
5 | /**
6 | * Returns the name of the module imported
7 | *
8 | * @param {ASTNode} node - A node to get.
9 | * @returns {string} the name of the module, or empty string if no name.
10 | */
11 | function getValue(node) {
12 | if (node != null && node.source != null && node.source.value != null) {
13 | return node.source.value.trim();
14 | }
15 |
16 | return '';
17 | }
18 |
19 | module.exports = {
20 | meta: {
21 | messages: {
22 | improperReactImport,
23 | },
24 | docs: {
25 | description: 'Force import * as React style',
26 | category: 'Best Practices',
27 | },
28 | schema: [
29 | {
30 | type: 'object',
31 | properties: {},
32 | additionalProperties: false,
33 | },
34 | ],
35 | },
36 |
37 | create: function(context) {
38 | return {
39 | ImportDeclaration: node => {
40 | const value = getValue(node);
41 |
42 | if (value === 'react') {
43 | const text = context.getSourceCode().getText(node);
44 | if (text === `import React from 'react';`) {
45 | context.report({
46 | node,
47 | message: improperReactImport,
48 | });
49 | }
50 | }
51 | },
52 | };
53 | },
54 | };
55 |
--------------------------------------------------------------------------------
/lib/rules/use-a11y-component.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {hasProp, elementType} = require('jsx-ast-utils');
4 |
5 | const useAnchorMessage = `Do not use HTML anchor () tags directly. Please use uikit/Anchor.`;
6 | const useClickableMessage = `Don't use onClick on non-button HTMLElement. Please use uikit/Clickable.`;
7 |
8 | module.exports = {
9 | meta: {
10 | messages: {
11 | useAnchorMessage,
12 | useClickableMessage,
13 | },
14 | docs: {
15 | description: 'Custom a11y component enforcement',
16 | category: 'Accessibility',
17 | },
18 | schema: [
19 | {
20 | type: 'object',
21 | properties: {},
22 | additionalProperties: false,
23 | },
24 | ],
25 | },
26 |
27 | create: function(context) {
28 | return {
29 | JSXOpeningElement: node => {
30 | const tag = elementType(node);
31 |
32 | if (tag === 'a') {
33 | // Don't use `a` use `Anchor`
34 | context.report({
35 | node,
36 | message: useAnchorMessage,
37 | });
38 | } else if (tag !== 'button' && /^[a-z]/.test(tag) && hasProp(node.attributes, 'onClick')) {
39 | // Don't use `onClick` on non-button HTMLElement, use Clickable
40 | context.report({
41 | node,
42 | message: useClickableMessage,
43 | });
44 | }
45 | },
46 | };
47 | },
48 | };
49 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eslint-plugin-discord",
3 | "version": "0.1.2",
4 | "description": "ESLint plugins for Discord",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "./node_modules/.bin/mocha tests/lib/index.js"
8 | },
9 | "keywords": [
10 | "eslint",
11 | "eslint-plugin",
12 | "eslintplugin"
13 | ],
14 | "devDependencies": {
15 | "babel-eslint": "9.0.0",
16 | "eslint": "4.19.1",
17 | "jsx-ast-utils": "2.0.1",
18 | "mocha": "5.0.5"
19 | },
20 | "private": true
21 | }
22 |
--------------------------------------------------------------------------------
/tests/lib/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const RuleTester = require('eslint').RuleTester;
4 |
5 | const ruleTester = new RuleTester({
6 | parserOptions: {
7 | ecmaVersion: 6,
8 | sourceType: 'module',
9 | ecmaFeatures: {
10 | jsx: true,
11 | },
12 | },
13 | });
14 |
15 | const rules = [
16 | require('./rules/react-import-style'),
17 | require('./rules/use-a11y-component'),
18 | require('./rules/camelcase-deprecation-support'),
19 | require('./rules/explicit-createref-type'),
20 | ];
21 |
22 | rules.forEach(rule => rule(ruleTester));
23 |
--------------------------------------------------------------------------------
/tests/lib/rules/camelcase-deprecation-support.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Tests for camelcase rule.
3 | * @author Nicholas C. Zakas
4 | */
5 |
6 | 'use strict';
7 |
8 | //------------------------------------------------------------------------------
9 | // Requirements
10 | //------------------------------------------------------------------------------
11 |
12 | const rule = require('../../../lib/rules/camelcase-deprecation-support');
13 |
14 | //------------------------------------------------------------------------------
15 | // Tests
16 | //------------------------------------------------------------------------------
17 |
18 | module.exports = ruleTester =>
19 | ruleTester.run('camelcase-deprecation-support', rule, {
20 | valid: [
21 | 'UNSAFE_componentDidMount = () => null;',
22 | 'firstName = "Nicholas"',
23 | 'FIRST_NAME = "Nicholas"',
24 | '__myPrivateVariable = "Patrick"',
25 | 'myPrivateVariable_ = "Patrick"',
26 | 'function doSomething(){}',
27 | 'do_something()',
28 | 'new do_something',
29 | 'new do_something()',
30 | 'foo.do_something()',
31 | 'var foo = bar.baz_boom;',
32 | 'var foo = bar.baz_boom.something;',
33 | 'foo.boom_pow.qux = bar.baz_boom.something;',
34 | 'if (bar.baz_boom) {}',
35 | 'var obj = { key: foo.bar_baz };',
36 | 'var arr = [foo.bar_baz];',
37 | '[foo.bar_baz]',
38 | 'var arr = [foo.bar_baz.qux];',
39 | '[foo.bar_baz.nesting]',
40 | 'if (foo.bar_baz === boom.bam_pow) { [foo.baz_boom] }',
41 | {
42 | code: 'var o = {key: 1}',
43 | options: [{properties: 'always'}],
44 | },
45 | {
46 | code: 'var o = {_leading: 1}',
47 | options: [{properties: 'always'}],
48 | },
49 | {
50 | code: 'var o = {trailing_: 1}',
51 | options: [{properties: 'always'}],
52 | },
53 | {
54 | code: 'var o = {bar_baz: 1}',
55 | options: [{properties: 'never'}],
56 | },
57 | {
58 | code: 'var o = {_leading: 1}',
59 | options: [{properties: 'never'}],
60 | },
61 | {
62 | code: 'var o = {trailing_: 1}',
63 | options: [{properties: 'never'}],
64 | },
65 | {
66 | code: 'obj.a_b = 2;',
67 | options: [{properties: 'never'}],
68 | },
69 | {
70 | code: 'obj._a = 2;',
71 | options: [{properties: 'always'}],
72 | },
73 | {
74 | code: 'obj.a_ = 2;',
75 | options: [{properties: 'always'}],
76 | },
77 | {
78 | code: 'obj._a = 2;',
79 | options: [{properties: 'never'}],
80 | },
81 | {
82 | code: 'obj.a_ = 2;',
83 | options: [{properties: 'never'}],
84 | },
85 | {
86 | code: 'var obj = {\n a_a: 1 \n};\n obj.a_b = 2;',
87 | options: [{properties: 'never'}],
88 | },
89 | {
90 | code: 'obj.foo_bar = function(){};',
91 | options: [{properties: 'never'}],
92 | },
93 | {
94 | code: 'var { category_id: category } = query;',
95 | parserOptions: {ecmaVersion: 6},
96 | },
97 | {
98 | code: 'var { _leading } = query;',
99 | parserOptions: {ecmaVersion: 6},
100 | },
101 | {
102 | code: 'var { trailing_ } = query;',
103 | parserOptions: {ecmaVersion: 6},
104 | },
105 | {
106 | code: 'import { camelCased } from "external module";',
107 | parserOptions: {ecmaVersion: 6, sourceType: 'module'},
108 | },
109 | {
110 | code: 'import { _leading } from "external module";',
111 | parserOptions: {ecmaVersion: 6, sourceType: 'module'},
112 | },
113 | {
114 | code: 'import { trailing_ } from "external module";',
115 | parserOptions: {ecmaVersion: 6, sourceType: 'module'},
116 | },
117 | {
118 | code: 'import { no_camelcased as camelCased } from "external-module";',
119 | parserOptions: {ecmaVersion: 6, sourceType: 'module'},
120 | },
121 | {
122 | code: 'import { no_camelcased as _leading } from "external-module";',
123 | parserOptions: {ecmaVersion: 6, sourceType: 'module'},
124 | },
125 | {
126 | code: 'import { no_camelcased as trailing_ } from "external-module";',
127 | parserOptions: {ecmaVersion: 6, sourceType: 'module'},
128 | },
129 | {
130 | code: 'import { no_camelcased as camelCased, anoterCamelCased } from "external-module";',
131 | parserOptions: {ecmaVersion: 6, sourceType: 'module'},
132 | },
133 | {
134 | code: 'function foo({ no_camelcased: camelCased }) {};',
135 | parserOptions: {ecmaVersion: 6},
136 | },
137 | {
138 | code: 'function foo({ no_camelcased: _leading }) {};',
139 | parserOptions: {ecmaVersion: 6},
140 | },
141 | {
142 | code: 'function foo({ no_camelcased: trailing_ }) {};',
143 | parserOptions: {ecmaVersion: 6},
144 | },
145 | {
146 | code: "function foo({ camelCased = 'default value' }) {};",
147 | parserOptions: {ecmaVersion: 6},
148 | },
149 | {
150 | code: "function foo({ _leading = 'default value' }) {};",
151 | parserOptions: {ecmaVersion: 6},
152 | },
153 | {
154 | code: "function foo({ trailing_ = 'default value' }) {};",
155 | parserOptions: {ecmaVersion: 6},
156 | },
157 | {
158 | code: 'function foo({ camelCased }) {};',
159 | parserOptions: {ecmaVersion: 6},
160 | },
161 | {
162 | code: 'function foo({ _leading }) {}',
163 | parserOptions: {ecmaVersion: 6},
164 | },
165 | {
166 | code: 'function foo({ trailing_ }) {}',
167 | parserOptions: {ecmaVersion: 6},
168 | },
169 | ],
170 | invalid: [
171 | {
172 | code: 'UNSAFE_component_will_mount = () => null;',
173 | errors: [
174 | {
175 | messageId: 'notCamelCase',
176 | data: {name: 'UNSAFE_component_will_mount'},
177 | type: 'Identifier',
178 | },
179 | ],
180 | },
181 | {
182 | code: 'first_name = "Nicholas"',
183 | errors: [
184 | {
185 | messageId: 'notCamelCase',
186 | data: {name: 'first_name'},
187 | type: 'Identifier',
188 | },
189 | ],
190 | },
191 | {
192 | code: '__private_first_name = "Patrick"',
193 | errors: [
194 | {
195 | messageId: 'notCamelCase',
196 | data: {name: '__private_first_name'},
197 | type: 'Identifier',
198 | },
199 | ],
200 | },
201 | {
202 | code: 'function foo_bar(){}',
203 | errors: [
204 | {
205 | messageId: 'notCamelCase',
206 | data: {name: 'foo_bar'},
207 | type: 'Identifier',
208 | },
209 | ],
210 | },
211 | {
212 | code: 'obj.foo_bar = function(){};',
213 | errors: [
214 | {
215 | messageId: 'notCamelCase',
216 | data: {name: 'foo_bar'},
217 | type: 'Identifier',
218 | },
219 | ],
220 | },
221 | {
222 | code: 'bar_baz.foo = function(){};',
223 | errors: [
224 | {
225 | messageId: 'notCamelCase',
226 | data: {name: 'bar_baz'},
227 | type: 'Identifier',
228 | },
229 | ],
230 | },
231 | {
232 | code: '[foo_bar.baz]',
233 | errors: [
234 | {
235 | messageId: 'notCamelCase',
236 | data: {name: 'foo_bar'},
237 | type: 'Identifier',
238 | },
239 | ],
240 | },
241 | {
242 | code: 'if (foo.bar_baz === boom.bam_pow) { [foo_bar.baz] }',
243 | errors: [
244 | {
245 | messageId: 'notCamelCase',
246 | data: {name: 'foo_bar'},
247 | type: 'Identifier',
248 | },
249 | ],
250 | },
251 | {
252 | code: 'foo.bar_baz = boom.bam_pow',
253 | errors: [
254 | {
255 | messageId: 'notCamelCase',
256 | data: {name: 'bar_baz'},
257 | type: 'Identifier',
258 | },
259 | ],
260 | },
261 | {
262 | code: 'var foo = { bar_baz: boom.bam_pow }',
263 | errors: [
264 | {
265 | messageId: 'notCamelCase',
266 | data: {name: 'bar_baz'},
267 | type: 'Identifier',
268 | },
269 | ],
270 | },
271 | {
272 | code: 'foo.qux.boom_pow = { bar: boom.bam_pow }',
273 | errors: [
274 | {
275 | messageId: 'notCamelCase',
276 | data: {name: 'boom_pow'},
277 | type: 'Identifier',
278 | },
279 | ],
280 | },
281 | {
282 | code: 'var o = {bar_baz: 1}',
283 | options: [{properties: 'always'}],
284 | errors: [
285 | {
286 | messageId: 'notCamelCase',
287 | data: {name: 'bar_baz'},
288 | type: 'Identifier',
289 | },
290 | ],
291 | },
292 | {
293 | code: 'obj.a_b = 2;',
294 | options: [{properties: 'always'}],
295 | errors: [
296 | {
297 | messageId: 'notCamelCase',
298 | data: {name: 'a_b'},
299 | type: 'Identifier',
300 | },
301 | ],
302 | },
303 | {
304 | code: 'var { category_id: category_id } = query;',
305 | parserOptions: {ecmaVersion: 6},
306 | errors: [
307 | {
308 | messageId: 'notCamelCase',
309 | data: {name: 'category_id'},
310 | type: 'Identifier',
311 | },
312 | ],
313 | },
314 | {
315 | code: 'var { category_id } = query;',
316 | parserOptions: {ecmaVersion: 6},
317 | errors: [
318 | {
319 | messageId: 'notCamelCase',
320 | data: {name: 'category_id'},
321 | type: 'Identifier',
322 | },
323 | ],
324 | },
325 | {
326 | code: 'var { category_id = 1 } = query;',
327 | parserOptions: {ecmaVersion: 6},
328 | errors: [
329 | {
330 | message: "Identifier 'category_id' is not in camel case.",
331 | type: 'Identifier',
332 | },
333 | ],
334 | },
335 | {
336 | code: 'import no_camelcased from "external-module";',
337 | parserOptions: {ecmaVersion: 6, sourceType: 'module'},
338 | errors: [
339 | {
340 | messageId: 'notCamelCase',
341 | data: {name: 'no_camelcased'},
342 | type: 'Identifier',
343 | },
344 | ],
345 | },
346 | {
347 | code: 'import * as no_camelcased from "external-module";',
348 | parserOptions: {ecmaVersion: 6, sourceType: 'module'},
349 | errors: [
350 | {
351 | messageId: 'notCamelCase',
352 | data: {name: 'no_camelcased'},
353 | type: 'Identifier',
354 | },
355 | ],
356 | },
357 | {
358 | code: 'import { no_camelcased } from "external-module";',
359 | parserOptions: {ecmaVersion: 6, sourceType: 'module'},
360 | errors: [
361 | {
362 | messageId: 'notCamelCase',
363 | data: {name: 'no_camelcased'},
364 | type: 'Identifier',
365 | },
366 | ],
367 | },
368 | {
369 | code: 'import { no_camelcased as no_camel_cased } from "external module";',
370 | parserOptions: {ecmaVersion: 6, sourceType: 'module'},
371 | errors: [
372 | {
373 | messageId: 'notCamelCase',
374 | data: {name: 'no_camel_cased'},
375 | type: 'Identifier',
376 | },
377 | ],
378 | },
379 | {
380 | code: 'import { camelCased as no_camel_cased } from "external module";',
381 | parserOptions: {ecmaVersion: 6, sourceType: 'module'},
382 | errors: [
383 | {
384 | messageId: 'notCamelCase',
385 | data: {name: 'no_camel_cased'},
386 | type: 'Identifier',
387 | },
388 | ],
389 | },
390 | {
391 | code: 'import { camelCased, no_camelcased } from "external-module";',
392 | parserOptions: {ecmaVersion: 6, sourceType: 'module'},
393 | errors: [
394 | {
395 | messageId: 'notCamelCase',
396 | data: {name: 'no_camelcased'},
397 | type: 'Identifier',
398 | },
399 | ],
400 | },
401 | {
402 | code: 'import { no_camelcased as camelCased, another_no_camelcased } from "external-module";',
403 | parserOptions: {ecmaVersion: 6, sourceType: 'module'},
404 | errors: [
405 | {
406 | messageId: 'notCamelCase',
407 | data: {name: 'another_no_camelcased'},
408 | type: 'Identifier',
409 | },
410 | ],
411 | },
412 | {
413 | code: 'import camelCased, { no_camelcased } from "external-module";',
414 | parserOptions: {ecmaVersion: 6, sourceType: 'module'},
415 | errors: [
416 | {
417 | messageId: 'notCamelCase',
418 | data: {name: 'no_camelcased'},
419 | type: 'Identifier',
420 | },
421 | ],
422 | },
423 | {
424 | code: 'import no_camelcased, { another_no_camelcased as camelCased } from "external-module";',
425 | parserOptions: {ecmaVersion: 6, sourceType: 'module'},
426 | errors: [
427 | {
428 | messageId: 'notCamelCase',
429 | data: {name: 'no_camelcased'},
430 | type: 'Identifier',
431 | },
432 | ],
433 | },
434 | {
435 | code: 'function foo({ no_camelcased }) {};',
436 | parserOptions: {ecmaVersion: 6},
437 | errors: [
438 | {
439 | message: "Identifier 'no_camelcased' is not in camel case.",
440 | type: 'Identifier',
441 | },
442 | ],
443 | },
444 | {
445 | code: "function foo({ no_camelcased = 'default value' }) {};",
446 | parserOptions: {ecmaVersion: 6},
447 | errors: [
448 | {
449 | message: "Identifier 'no_camelcased' is not in camel case.",
450 | type: 'Identifier',
451 | },
452 | ],
453 | },
454 | {
455 | code: 'const no_camelcased = 0; function foo({ camelcased_value = no_camelcased}) {}',
456 | parserOptions: {ecmaVersion: 6},
457 | errors: [
458 | {
459 | message: "Identifier 'no_camelcased' is not in camel case.",
460 | type: 'Identifier',
461 | },
462 | {
463 | message: "Identifier 'camelcased_value' is not in camel case.",
464 | type: 'Identifier',
465 | },
466 | ],
467 | },
468 | {
469 | code: 'const { bar: no_camelcased } = foo;',
470 | parserOptions: {ecmaVersion: 6},
471 | errors: [
472 | {
473 | message: "Identifier 'no_camelcased' is not in camel case.",
474 | type: 'Identifier',
475 | },
476 | ],
477 | },
478 | {
479 | code: 'function foo({ value_1: my_default }) {}',
480 | parserOptions: {ecmaVersion: 6},
481 | errors: [
482 | {
483 | message: "Identifier 'my_default' is not in camel case.",
484 | type: 'Identifier',
485 | },
486 | ],
487 | },
488 | {
489 | code: 'function foo({ isCamelcased: no_camelcased }) {};',
490 | parserOptions: {ecmaVersion: 6},
491 | errors: [
492 | {
493 | message: "Identifier 'no_camelcased' is not in camel case.",
494 | type: 'Identifier',
495 | },
496 | ],
497 | },
498 | {
499 | code: 'var { foo: bar_baz = 1 } = quz;',
500 | parserOptions: {ecmaVersion: 6},
501 | errors: [
502 | {
503 | message: "Identifier 'bar_baz' is not in camel case.",
504 | type: 'Identifier',
505 | },
506 | ],
507 | },
508 | {
509 | code: 'const { no_camelcased = false } = bar;',
510 | parserOptions: {ecmaVersion: 6},
511 | errors: [
512 | {
513 | message: "Identifier 'no_camelcased' is not in camel case.",
514 | type: 'Identifier',
515 | },
516 | ],
517 | },
518 | ],
519 | });
520 |
--------------------------------------------------------------------------------
/tests/lib/rules/explicit-createref-type.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const rule = require("../../../lib/rules/explicit-createref-type");
4 | const parser = require.resolve("babel-eslint");
5 |
6 | module.exports = ruleTester =>
7 | ruleTester.run("explicit-createref-type", rule, {
8 | valid: [
9 | {
10 | parser,
11 | code: `
12 | /* @flow */
13 |
14 | import * as React from 'react';
15 |
16 | class Test {
17 | a: {current: React.ElementRef<*> | null} = React.createRef();
18 | b: * = React.createRef();
19 | c = React.createElement();
20 | d = {};
21 | }
22 | `
23 | },
24 | {
25 | parser,
26 | code: `
27 | /* @flow */
28 |
29 | import * as React from 'react';
30 |
31 | class Test {
32 | a = React.createRef<*>();
33 | }
34 | `
35 | }
36 | ],
37 |
38 | invalid: [
39 | {
40 | parser,
41 | code: `
42 | /* @flow */
43 | import * as React from 'react';
44 | class Test { a = React.createRef(); }
45 | `,
46 | errors: [{ messageId: "explicitCreateRefTypeMessage" }]
47 | }
48 | ]
49 | });
50 |
--------------------------------------------------------------------------------
/tests/lib/rules/react-import-style.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const rule = require('../../../lib/rules/react-import-style');
4 |
5 | module.exports = ruleTester =>
6 | ruleTester.run('react-import-style', rule, {
7 | valid: [
8 | `
9 | /* @flow */
10 |
11 | import * as React from 'react';
12 | import B from 'B';
13 | `,
14 | `import A from 'A';`,
15 | ],
16 |
17 | invalid: [
18 | {
19 | code: `import React from 'react';`,
20 | errors: [{messageId: 'improperReactImport'}],
21 | },
22 | ],
23 | });
24 |
--------------------------------------------------------------------------------
/tests/lib/rules/use-a11y-component.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const rule = require('../../../lib/rules/use-a11y-component');
4 |
5 | const onClick = `onClick={()=>{}}`;
6 |
7 | module.exports = ruleTester =>
8 | ruleTester.run('use-a11y-component', rule, {
9 | valid: [`