@agilebot/eslint-plugin 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,105 +1,105 @@
1
- const { ESLintUtils } = require('@typescript-eslint/utils');
2
-
3
- /**
4
- * Auto-fix util.
5
- * Ensures that passed key is imported from 'react' package.
6
- */
7
- function* updateImportStatement(context, fixer, key) {
8
- const sourceCode = context.getSourceCode();
9
- const importNode = sourceCode.ast.body.find(
10
- node => node.type === 'ImportDeclaration' && node.source.value === 'react'
11
- );
12
-
13
- // No import from 'react' - create import statement
14
- if (!importNode) {
15
- yield fixer.insertTextBefore(
16
- sourceCode.ast.body[0],
17
- `import { ${key} } from 'react';\n`
18
- );
19
-
20
- return;
21
- }
22
-
23
- // Only default import from 'react' - add named imports section
24
- if (
25
- importNode.specifiers.length === 1 &&
26
- importNode.specifiers[0].type === 'ImportDefaultSpecifier'
27
- ) {
28
- yield fixer.insertTextAfter(importNode.specifiers[0], `, { ${key} }`);
29
-
30
- return;
31
- }
32
-
33
- const alreadyImportedKeys = importNode.specifiers
34
- .filter(specifier => specifier.type === 'ImportSpecifier')
35
- .map(specifier => specifier.imported.name);
36
-
37
- // Named imports section is present and current key is already imported - do nothing
38
- if (alreadyImportedKeys.includes(key)) {
39
- return;
40
- }
41
-
42
- // Named imports section is present and current key is not imported yet - add it to named imports section
43
- yield fixer.insertTextAfter(importNode.specifiers.slice().pop(), `, ${key}`);
44
- }
45
-
46
- /** @type {import('eslint').Rule.RuleModule} */
47
- module.exports = ESLintUtils.RuleCreator.withoutDocs({
48
- defaultOptions: [],
49
- meta: {
50
- type: 'layout',
51
- fixable: 'code',
52
- docs: {
53
- description:
54
- 'Enforce importing each member of React namespace separately instead of accessing them through React namespace',
55
- category: 'Layout & Formatting'
56
- },
57
- messages: {
58
- illegalReactPropertyAccess:
59
- 'Illegal React property access: {{name}}. Use named import instead.'
60
- }
61
- },
62
-
63
- create(context) {
64
- return {
65
- // Analyze TS types declarations
66
- TSQualifiedName(node) {
67
- // Do nothing to types that are ending with 'Event' as they will overlap with global event types otherwise
68
- if (node.left.name !== 'React' || node.right.name.endsWith('Event')) {
69
- return;
70
- }
71
-
72
- context.report({
73
- node,
74
- messageId: 'illegalReactPropertyAccess',
75
- data: {
76
- name: node.right.name
77
- },
78
- *fix(fixer) {
79
- yield fixer.replaceText(node, node.right.name);
80
- yield* updateImportStatement(context, fixer, node.right.name);
81
- }
82
- });
83
- },
84
-
85
- // Analyze expressions for React.* access
86
- MemberExpression(node) {
87
- if (node.object.name !== 'React') {
88
- return;
89
- }
90
-
91
- context.report({
92
- node,
93
- messageId: 'illegalReactPropertyAccess',
94
- data: {
95
- name: node.property.name
96
- },
97
- *fix(fixer) {
98
- yield fixer.replaceText(node, node.property.name);
99
- yield* updateImportStatement(context, fixer, node.property.name);
100
- }
101
- });
102
- }
103
- };
104
- }
105
- });
1
+ const { ESLintUtils } = require('@typescript-eslint/utils');
2
+
3
+ /**
4
+ * Auto-fix util.
5
+ * Ensures that passed key is imported from 'react' package.
6
+ */
7
+ function* updateImportStatement(context, fixer, key) {
8
+ const sourceCode = context.getSourceCode();
9
+ const importNode = sourceCode.ast.body.find(
10
+ node => node.type === 'ImportDeclaration' && node.source.value === 'react'
11
+ );
12
+
13
+ // No import from 'react' - create import statement
14
+ if (!importNode) {
15
+ yield fixer.insertTextBefore(
16
+ sourceCode.ast.body[0],
17
+ `import { ${key} } from 'react';\n`
18
+ );
19
+
20
+ return;
21
+ }
22
+
23
+ // Only default import from 'react' - add named imports section
24
+ if (
25
+ importNode.specifiers.length === 1 &&
26
+ importNode.specifiers[0].type === 'ImportDefaultSpecifier'
27
+ ) {
28
+ yield fixer.insertTextAfter(importNode.specifiers[0], `, { ${key} }`);
29
+
30
+ return;
31
+ }
32
+
33
+ const alreadyImportedKeys = importNode.specifiers
34
+ .filter(specifier => specifier.type === 'ImportSpecifier')
35
+ .map(specifier => specifier.imported.name);
36
+
37
+ // Named imports section is present and current key is already imported - do nothing
38
+ if (alreadyImportedKeys.includes(key)) {
39
+ return;
40
+ }
41
+
42
+ // Named imports section is present and current key is not imported yet - add it to named imports section
43
+ yield fixer.insertTextAfter([...importNode.specifiers].pop(), `, ${key}`);
44
+ }
45
+
46
+ /** @type {import('eslint').Rule.RuleModule} */
47
+ module.exports = ESLintUtils.RuleCreator.withoutDocs({
48
+ defaultOptions: [],
49
+ meta: {
50
+ type: 'layout',
51
+ fixable: 'code',
52
+ docs: {
53
+ description:
54
+ 'Enforce importing each member of React namespace separately instead of accessing them through React namespace',
55
+ category: 'Layout & Formatting'
56
+ },
57
+ messages: {
58
+ illegalReactPropertyAccess:
59
+ 'Illegal React property access: {{name}}. Use named import instead.'
60
+ }
61
+ },
62
+
63
+ create(context) {
64
+ return {
65
+ // Analyze TS types declarations
66
+ TSQualifiedName(node) {
67
+ // Do nothing to types that are ending with 'Event' as they will overlap with global event types otherwise
68
+ if (node.left.name !== 'React' || node.right.name.endsWith('Event')) {
69
+ return;
70
+ }
71
+
72
+ context.report({
73
+ node,
74
+ messageId: 'illegalReactPropertyAccess',
75
+ data: {
76
+ name: node.right.name
77
+ },
78
+ *fix(fixer) {
79
+ yield fixer.replaceText(node, node.right.name);
80
+ yield* updateImportStatement(context, fixer, node.right.name);
81
+ }
82
+ });
83
+ },
84
+
85
+ // Analyze expressions for React.* access
86
+ MemberExpression(node) {
87
+ if (node.object.name !== 'React') {
88
+ return;
89
+ }
90
+
91
+ context.report({
92
+ node,
93
+ messageId: 'illegalReactPropertyAccess',
94
+ data: {
95
+ name: node.property.name
96
+ },
97
+ *fix(fixer) {
98
+ yield fixer.replaceText(node, node.property.name);
99
+ yield* updateImportStatement(context, fixer, node.property.name);
100
+ }
101
+ });
102
+ }
103
+ };
104
+ }
105
+ });
@@ -1,43 +1,43 @@
1
- const { getStyesObj, isCamelCase } = require('../../util/tss');
2
-
3
- module.exports = {
4
- meta: {
5
- type: 'problem'
6
- },
7
- create: function rule(context) {
8
- return {
9
- CallExpression(node) {
10
- const stylesObj = getStyesObj(node);
11
-
12
- if (typeof stylesObj === 'undefined') {
13
- return;
14
- }
15
-
16
- stylesObj.properties.forEach(property => {
17
- if (property.computed) {
18
- // Skip over computed properties for now.
19
- // e.g. `{ [foo]: { ... } }`
20
- return;
21
- }
22
-
23
- if (
24
- property.type === 'ExperimentalSpreadProperty' ||
25
- property.type === 'SpreadElement'
26
- ) {
27
- // Skip over object spread for now.
28
- // e.g. `{ ...foo }`
29
- return;
30
- }
31
-
32
- const className = property.key.value || property.key.name;
33
- if (!isCamelCase(className)) {
34
- context.report(
35
- property,
36
- `Class \`${className}\` must be camelCase in makeStyles.`
37
- );
38
- }
39
- });
40
- }
41
- };
42
- }
43
- };
1
+ const { getStyesObj, isCamelCase } = require('../../util/tss');
2
+
3
+ module.exports = {
4
+ meta: {
5
+ type: 'problem'
6
+ },
7
+ create: function rule(context) {
8
+ return {
9
+ CallExpression(node) {
10
+ const stylesObj = getStyesObj(node);
11
+
12
+ if (stylesObj === undefined) {
13
+ return;
14
+ }
15
+
16
+ stylesObj.properties.forEach(property => {
17
+ if (property.computed) {
18
+ // Skip over computed properties for now.
19
+ // e.g. `{ [foo]: { ... } }`
20
+ return;
21
+ }
22
+
23
+ if (
24
+ property.type === 'ExperimentalSpreadProperty' ||
25
+ property.type === 'SpreadElement'
26
+ ) {
27
+ // Skip over object spread for now.
28
+ // e.g. `{ ...foo }`
29
+ return;
30
+ }
31
+
32
+ const className = property.key.value || property.key.name;
33
+ if (!isCamelCase(className)) {
34
+ context.report(
35
+ property,
36
+ `Class \`${className}\` must be camelCase in makeStyles.`
37
+ );
38
+ }
39
+ });
40
+ }
41
+ };
42
+ }
43
+ };
@@ -1,59 +1,58 @@
1
- const { getStyesObj } = require('../../util/tss');
2
-
3
- module.exports = {
4
- meta: {
5
- type: 'problem',
6
- docs: {
7
- description:
8
- 'Enforce the use of color variables instead of color codes within makeStyles'
9
- }
10
- },
11
- create: function (context) {
12
- const parserOptions = context.parserOptions;
13
- if (!parserOptions || !parserOptions.project) {
14
- return {};
15
- }
16
-
17
- return {
18
- CallExpression(node) {
19
- const stylesObj = getStyesObj(node);
20
- if (!stylesObj) {
21
- return;
22
- }
23
-
24
- // Check for color codes inside the stylesObj
25
- function checkColorLiteral(value) {
26
- if (value.type === 'Literal' && typeof value.value === 'string') {
27
- const colorCodePattern =
28
- // eslint-disable-next-line max-len
29
- /#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})|rgb\?\(\s*(\d{1,3}\s*,\s*){2}\d{1,3}(?:\s*,\s*\d*(?:\.\d+)?)?\s*\)/g;
30
- const isColorCode = colorCodePattern.test(value.value);
31
- if (isColorCode) {
32
- context.report({
33
- node: value,
34
- message:
35
- 'Use color variables instead of color codes in makeStyles.'
36
- });
37
- }
38
- }
39
- }
40
-
41
- function loopStylesObj(obj) {
42
- if (obj && obj.type === 'ObjectExpression') {
43
- obj.properties.forEach(property => {
44
- if (property.type === 'Property' && property.value) {
45
- if (property.value.type === 'ObjectExpression') {
46
- loopStylesObj(property.value);
47
- } else {
48
- checkColorLiteral(property.value);
49
- }
50
- }
51
- });
52
- }
53
- }
54
-
55
- loopStylesObj(stylesObj);
56
- }
57
- };
58
- }
59
- };
1
+ const { getStyesObj } = require('../../util/tss');
2
+
3
+ module.exports = {
4
+ meta: {
5
+ type: 'problem',
6
+ docs: {
7
+ description:
8
+ 'Enforce the use of color variables instead of color codes within makeStyles'
9
+ }
10
+ },
11
+ create: function (context) {
12
+ const parserOptions = context.parserOptions;
13
+ if (!parserOptions || !parserOptions.project) {
14
+ return {};
15
+ }
16
+
17
+ return {
18
+ CallExpression(node) {
19
+ const stylesObj = getStyesObj(node);
20
+ if (!stylesObj) {
21
+ return;
22
+ }
23
+
24
+ // Check for color codes inside the stylesObj
25
+ function checkColorLiteral(value) {
26
+ if (value.type === 'Literal' && typeof value.value === 'string') {
27
+ const colorCodePattern =
28
+ /#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})|rgb\?\(\s*(\d{1,3}\s*,\s*){2}\d{1,3}(?:\s*,\s*\d*(?:\.\d+)?)?\s*\)/g;
29
+ const isColorCode = colorCodePattern.test(value.value);
30
+ if (isColorCode) {
31
+ context.report({
32
+ node: value,
33
+ message:
34
+ 'Use color variables instead of color codes in makeStyles.'
35
+ });
36
+ }
37
+ }
38
+ }
39
+
40
+ function loopStylesObj(obj) {
41
+ if (obj && obj.type === 'ObjectExpression') {
42
+ obj.properties.forEach(property => {
43
+ if (property.type === 'Property' && property.value) {
44
+ if (property.value.type === 'ObjectExpression') {
45
+ loopStylesObj(property.value);
46
+ } else {
47
+ checkColorLiteral(property.value);
48
+ }
49
+ }
50
+ });
51
+ }
52
+ }
53
+
54
+ loopStylesObj(stylesObj);
55
+ }
56
+ };
57
+ }
58
+ };
@@ -1,108 +1,108 @@
1
- const { getBasicIdentifier, getStyesObj } = require('../../util/tss');
2
-
3
- module.exports = {
4
- meta: {
5
- type: 'problem'
6
- },
7
- create: function rule(context) {
8
- const usedClasses = {};
9
- const definedClasses = {};
10
-
11
- return {
12
- CallExpression(node) {
13
- const stylesObj = getStyesObj(node);
14
-
15
- if (typeof stylesObj === 'undefined') {
16
- return;
17
- }
18
-
19
- stylesObj.properties.forEach(property => {
20
- if (property.computed) {
21
- // Skip over computed properties for now.
22
- // e.g. `{ [foo]: { ... } }`
23
- return;
24
- }
25
-
26
- if (
27
- property.type === 'ExperimentalSpreadProperty' ||
28
- property.type === 'SpreadElement'
29
- ) {
30
- // Skip over object spread for now.
31
- // e.g. `{ ...foo }`
32
- return;
33
- }
34
- definedClasses[property.key.value || property.key.name] = property;
35
- });
36
- },
37
-
38
- MemberExpression(node) {
39
- if (
40
- node.object.type === 'Identifier' &&
41
- node.object.name === 'classes'
42
- ) {
43
- const whichClass = getBasicIdentifier(node.property);
44
- if (whichClass) {
45
- usedClasses[whichClass] = true;
46
- }
47
- return;
48
- }
49
-
50
- const classIdentifier = getBasicIdentifier(node.property);
51
- if (!classIdentifier) {
52
- // props['foo' + bar].baz
53
- return;
54
- }
55
-
56
- if (classIdentifier !== 'classes') {
57
- // props.foo.bar
58
- return;
59
- }
60
-
61
- const { parent } = node;
62
-
63
- if (parent.type !== 'MemberExpression') {
64
- // foo.styles
65
- return;
66
- }
67
-
68
- if (
69
- node.object.object &&
70
- node.object.object.type !== 'ThisExpression'
71
- ) {
72
- // foo.foo.styles
73
- return;
74
- }
75
-
76
- const propsIdentifier = getBasicIdentifier(parent.object);
77
- if (propsIdentifier && propsIdentifier !== 'props') {
78
- return;
79
- }
80
- if (!propsIdentifier && parent.object.type !== 'MemberExpression') {
81
- return;
82
- }
83
-
84
- if (parent.parent.type === 'MemberExpression') {
85
- // this.props.props.styles
86
- return;
87
- }
88
-
89
- const parentClassIdentifier = getBasicIdentifier(parent.property);
90
- if (parentClassIdentifier) {
91
- usedClasses[parentClassIdentifier] = true;
92
- }
93
- },
94
- 'Program:exit': () => {
95
- // Now we know all of the defined classes and used classes, so we can
96
- // see if there are any defined classes that are not used.
97
- Object.keys(definedClasses).forEach(definedClassKey => {
98
- if (!usedClasses[definedClassKey]) {
99
- context.report(
100
- definedClasses[definedClassKey],
101
- `Class \`${definedClassKey}\` is unused`
102
- );
103
- }
104
- });
105
- }
106
- };
107
- }
108
- };
1
+ const { getBasicIdentifier, getStyesObj } = require('../../util/tss');
2
+
3
+ module.exports = {
4
+ meta: {
5
+ type: 'problem'
6
+ },
7
+ create: function rule(context) {
8
+ const usedClasses = {};
9
+ const definedClasses = {};
10
+
11
+ return {
12
+ CallExpression(node) {
13
+ const stylesObj = getStyesObj(node);
14
+
15
+ if (stylesObj === undefined) {
16
+ return;
17
+ }
18
+
19
+ stylesObj.properties.forEach(property => {
20
+ if (property.computed) {
21
+ // Skip over computed properties for now.
22
+ // e.g. `{ [foo]: { ... } }`
23
+ return;
24
+ }
25
+
26
+ if (
27
+ property.type === 'ExperimentalSpreadProperty' ||
28
+ property.type === 'SpreadElement'
29
+ ) {
30
+ // Skip over object spread for now.
31
+ // e.g. `{ ...foo }`
32
+ return;
33
+ }
34
+ definedClasses[property.key.value || property.key.name] = property;
35
+ });
36
+ },
37
+
38
+ MemberExpression(node) {
39
+ if (
40
+ node.object.type === 'Identifier' &&
41
+ node.object.name === 'classes'
42
+ ) {
43
+ const whichClass = getBasicIdentifier(node.property);
44
+ if (whichClass) {
45
+ usedClasses[whichClass] = true;
46
+ }
47
+ return;
48
+ }
49
+
50
+ const classIdentifier = getBasicIdentifier(node.property);
51
+ if (!classIdentifier) {
52
+ // props['foo' + bar].baz
53
+ return;
54
+ }
55
+
56
+ if (classIdentifier !== 'classes') {
57
+ // props.foo.bar
58
+ return;
59
+ }
60
+
61
+ const { parent } = node;
62
+
63
+ if (parent.type !== 'MemberExpression') {
64
+ // foo.styles
65
+ return;
66
+ }
67
+
68
+ if (
69
+ node.object.object &&
70
+ node.object.object.type !== 'ThisExpression'
71
+ ) {
72
+ // foo.foo.styles
73
+ return;
74
+ }
75
+
76
+ const propsIdentifier = getBasicIdentifier(parent.object);
77
+ if (propsIdentifier && propsIdentifier !== 'props') {
78
+ return;
79
+ }
80
+ if (!propsIdentifier && parent.object.type !== 'MemberExpression') {
81
+ return;
82
+ }
83
+
84
+ if (parent.parent.type === 'MemberExpression') {
85
+ // this.props.props.styles
86
+ return;
87
+ }
88
+
89
+ const parentClassIdentifier = getBasicIdentifier(parent.property);
90
+ if (parentClassIdentifier) {
91
+ usedClasses[parentClassIdentifier] = true;
92
+ }
93
+ },
94
+ 'Program:exit': () => {
95
+ // Now we know all of the defined classes and used classes, so we can
96
+ // see if there are any defined classes that are not used.
97
+ Object.keys(definedClasses).forEach(definedClassKey => {
98
+ if (!usedClasses[definedClassKey]) {
99
+ context.report(
100
+ definedClasses[definedClassKey],
101
+ `Class \`${definedClassKey}\` is unused`
102
+ );
103
+ }
104
+ });
105
+ }
106
+ };
107
+ }
108
+ };