@automattic/eslint-plugin-wpvip 0.5.1 → 0.5.2

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.
@@ -0,0 +1 @@
1
+ module.exports = require('./javascript');
package/configs/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  module.exports = {
2
- base: require('./javascript'), // synonym for javascript
2
+ base: require('./base'), // synonym for javascript
3
3
  cli: require('./cli'),
4
4
  formatting: require('./formatting'),
5
5
  javascript: require('./javascript'),
@@ -100,10 +100,6 @@ module.exports = {
100
100
  // will not be awaited in the outer scope.
101
101
  '@automattic/wpvip/no-async-foreach': 'error',
102
102
 
103
- // Variables that are potentially not needed before a return statement can
104
- // be assigned after the return.
105
- '@automattic/wpvip/no-unused-vars-before-return': 'error',
106
-
107
103
  // Unguarded getRangeAt calls can throw errors in some browsers.
108
104
  '@automattic/wpvip/no-unguarded-get-range-at': 'error',
109
105
 
package/configs/react.js CHANGED
@@ -7,7 +7,7 @@ module.exports = {
7
7
  extends: [
8
8
  'plugin:react/recommended',
9
9
  'plugin:react-hooks/recommended',
10
- require('./jsx-ally'),
10
+ 'plugin:jsx-a11y/recommended',
11
11
  ],
12
12
 
13
13
  parserOptions: {
@@ -22,16 +22,24 @@ module.exports = {
22
22
  },
23
23
  },
24
24
 
25
- plugins: ['@automattic/wpvip', 'react', 'react-hooks'],
25
+ plugins: ['@automattic/wpvip', 'jsx-a11y', 'react', 'react-hooks'],
26
26
 
27
27
  rules: {
28
- '@automattic/wpvip/no-unused-vars-before-return': [
28
+ 'jsx-a11y/label-has-associated-control': [
29
29
  'error',
30
30
  {
31
- excludePattern: '^use',
31
+ assert: 'htmlFor',
32
32
  },
33
33
  ],
34
34
 
35
+ 'jsx-a11y/media-has-caption': 'off',
36
+
37
+ 'jsx-a11y/no-noninteractive-tabindex': 'off',
38
+
39
+ 'jsx-a11y/role-has-required-aria-props': 'off',
40
+
41
+ 'jsx-quotes': 'error',
42
+
35
43
  'react/display-name': 'off',
36
44
 
37
45
  'react/jsx-curly-spacing': [
@@ -17,8 +17,6 @@ module.exports = {
17
17
  * to "off"). If a rule is already set to a warning, do not disable it.
18
18
  */
19
19
  rules: {
20
- '@automattic/wpvip/no-unused-vars-before-return': 'warn',
21
-
22
20
  complexity: 'warn',
23
21
 
24
22
  eqeqeq: 'warn',
package/jest.config.js ADDED
@@ -0,0 +1,5 @@
1
+ /** @type {import('ts-jest').JestConfigWithTsJest} */
2
+ module.exports = {
3
+ preset: 'ts-jest',
4
+ testEnvironment: 'node',
5
+ };
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@automattic/eslint-plugin-wpvip",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "ESLint plugin for internal WordPress VIP projects",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
- "jest": "jest",
7
+ "check-types": "tsc __tests__/**/*.ts",
8
+ "jest": "npm run link-plugin && jest",
8
9
  "jest:update-snapshot": "jest --updateSnapshot",
9
10
  "link-plugin": "mkdir -p ./node_modules/@automattic; ln -fns $(pwd) ./node_modules/@automattic/eslint-plugin-wpvip",
10
11
  "lint": "npm run link-plugin && eslint .",
11
- "test": "jest"
12
+ "test": "npm run jest"
12
13
  },
13
14
  "repository": {
14
15
  "type": "git",
@@ -47,9 +48,13 @@
47
48
  "eslint": ">=8"
48
49
  },
49
50
  "devDependencies": {
51
+ "@tsconfig/node18": "1.0.1",
52
+ "@types/eslint": "8.37.0",
53
+ "@types/jest": "29.5.0",
50
54
  "eslint": "8.35.0",
51
55
  "jest": "29.5.0",
52
56
  "prettier": "2.8.4",
57
+ "ts-jest": "29.0.5",
53
58
  "typescript": "4.9.5"
54
59
  }
55
60
  }
package/rules/index.js CHANGED
@@ -5,5 +5,4 @@ module.exports = {
5
5
  'dependency-group': require('./dependency-group'),
6
6
  'no-async-foreach': require('./no-async-foreach'),
7
7
  'no-unguarded-get-range-at': require('./no-unguarded-get-range-at'),
8
- 'no-unused-vars-before-return': require('./no-unused-vars-before-return'),
9
8
  };
@@ -1,21 +0,0 @@
1
- /**
2
- * Based on:
3
- * https://github.com/WordPress/gutenberg/blob/%40wordpress/eslint-plugin%4014.1.0/packages/eslint-plugin/configs/jsx-a11y.js
4
- */
5
-
6
- module.exports = {
7
- extends: ['plugin:jsx-a11y/recommended'],
8
- plugins: ['jsx-a11y'],
9
- rules: {
10
- 'jsx-a11y/label-has-associated-control': [
11
- 'error',
12
- {
13
- assert: 'htmlFor',
14
- },
15
- ],
16
- 'jsx-a11y/media-has-caption': 'off',
17
- 'jsx-a11y/no-noninteractive-tabindex': 'off',
18
- 'jsx-a11y/role-has-required-aria-props': 'off',
19
- 'jsx-quotes': 'error',
20
- },
21
- };
@@ -1,155 +0,0 @@
1
- /**
2
- * From:
3
- * https://github.com/WordPress/gutenberg/blob/%40wordpress/eslint-plugin%4014.1.0/packages/eslint-plugin/rules/no-unused-vars-before-return.js
4
- */
5
-
6
- /** @typedef {import('eslint').Scope.Scope} ESLintScope */
7
- /** @typedef {import('eslint').Rule.RuleContext} ESLintRuleContext */
8
- /** @typedef {import('estree').Node} ESTreeNode */
9
-
10
- /**
11
- * Mapping of function scope objects to a set of identified JSX identifiers
12
- * within that scope.
13
- *
14
- * @type {WeakMap<ESLintScope,Set<ESTreeNode>>}
15
- */
16
- const FUNCTION_SCOPE_JSX_IDENTIFIERS = new WeakMap();
17
-
18
- /**
19
- * Returns the closest function scope for the current ESLint context object, or
20
- * undefined if it cannot be determined.
21
- *
22
- * @param {ESLintRuleContext} context ESLint context object.
23
- *
24
- * @return {ESLintScope|undefined} Function scope, if known.
25
- */
26
- function getClosestFunctionScope(context) {
27
- let functionScope = context.getScope();
28
- while (functionScope.type !== 'function' && functionScope.upper) {
29
- functionScope = functionScope.upper;
30
- }
31
-
32
- return functionScope;
33
- }
34
-
35
- module.exports = /** @type {import('eslint').Rule} */ ({
36
- meta: {
37
- type: 'problem',
38
- schema: [
39
- {
40
- type: 'object',
41
- properties: {
42
- excludePattern: {
43
- type: 'string',
44
- },
45
- },
46
- additionalProperties: false,
47
- },
48
- ],
49
- },
50
- /**
51
- * @param {ESLintRuleContext} context Rule context.
52
- */
53
- create(context) {
54
- const options = context.options[0] || {};
55
- const { excludePattern } = options;
56
-
57
- /**
58
- * Given an Espree VariableDeclarator node, returns true if the node
59
- * can be exempted from consideration as unused, or false otherwise. A
60
- * node can be exempt if it destructures to multiple variables, since
61
- * those other variables may be used prior to the return statement. A
62
- * future enhancement could validate that they are in-fact referenced.
63
- *
64
- * @param {Object} node Node to test.
65
- *
66
- * @return {boolean} Whether declarator is emempt from consideration.
67
- */
68
- function isExemptObjectDestructureDeclarator(node) {
69
- return node.id.type === 'ObjectPattern' && node.id.properties.length > 1;
70
- }
71
-
72
- return {
73
- JSXIdentifier(node) {
74
- // Currently, a scope's variable references does not include JSX
75
- // identifiers. Account for this by visiting JSX identifiers
76
- // first, and tracking them in a map per function scope, which
77
- // is later merged with the known variable references.
78
- const functionScope = getClosestFunctionScope(context);
79
- if (!functionScope) {
80
- return;
81
- }
82
-
83
- if (!FUNCTION_SCOPE_JSX_IDENTIFIERS.has(functionScope)) {
84
- FUNCTION_SCOPE_JSX_IDENTIFIERS.set(functionScope, new Set());
85
- }
86
-
87
- FUNCTION_SCOPE_JSX_IDENTIFIERS.get(functionScope).add(node);
88
- },
89
- 'ReturnStatement:exit'(node) {
90
- const functionScope = getClosestFunctionScope(context);
91
- if (!functionScope) {
92
- return;
93
- }
94
-
95
- for (const variable of functionScope.variables) {
96
- const declaratorCandidate = variable.defs.find((def) => {
97
- return (
98
- def.node.type === 'VariableDeclarator' &&
99
- // Allow declarations which are not initialized.
100
- def.node.init &&
101
- // Target function calls as "expensive".
102
- def.node.init.type === 'CallExpression' &&
103
- // Allow unused if part of an object destructuring.
104
- !isExemptObjectDestructureDeclarator(def.node) &&
105
- // Only target assignments preceding `return`.
106
- def.node.range[1] < node.range[1]
107
- );
108
- });
109
-
110
- if (!declaratorCandidate) {
111
- continue;
112
- }
113
-
114
- if (
115
- excludePattern !== undefined &&
116
- // eslint-disable-next-line security/detect-non-literal-regexp
117
- new RegExp(excludePattern).test(
118
- declaratorCandidate.node.init.callee.name
119
- )
120
- ) {
121
- continue;
122
- }
123
-
124
- // The first entry in `references` is the declaration
125
- // itself, which can be ignored.
126
- const identifiers = variable.references
127
- .slice(1)
128
- .map((reference) => reference.identifier);
129
-
130
- // Merge with any JSX identifiers in scope, if any.
131
- if (FUNCTION_SCOPE_JSX_IDENTIFIERS.has(functionScope)) {
132
- const jsxIdentifiers =
133
- FUNCTION_SCOPE_JSX_IDENTIFIERS.get(functionScope);
134
-
135
- identifiers.push(...jsxIdentifiers);
136
- }
137
-
138
- const isUsedBeforeReturn = identifiers.some(
139
- (identifier) => identifier.range[1] < node.range[1]
140
- );
141
-
142
- if (isUsedBeforeReturn) {
143
- continue;
144
- }
145
-
146
- context.report(
147
- declaratorCandidate.node,
148
- 'Variables should not be assigned until just prior its first reference. ' +
149
- 'An early return statement may leave this variable unused.'
150
- );
151
- }
152
- },
153
- };
154
- },
155
- });