eslint-config-uphold 6.2.0 → 6.3.0

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.
package/README.md CHANGED
@@ -27,19 +27,25 @@ const uphold = require('eslint-config-uphold');
27
27
  module.exports = uphold;
28
28
  ```
29
29
 
30
- If you'd like to extend the config, you can do so like this:
30
+ If you'd like to extend the config, or change rules, you can do so like this:
31
31
 
32
32
  ```js
33
+ const { defineConfig } = require('eslint/config');
33
34
  const uphold = require('eslint-config-uphold');
34
35
  const yourPlugin = require('your-eslint-plugin');
35
36
 
36
- module.exports = [
37
- ...uphold,
38
- plugins: {
39
- ...uphold[0].plugins,
40
- yourPlugin,
37
+ module.exports = defineConfig([
38
+ {
39
+ extends: [uphold],
40
+ name: 'uphold-config',
41
+ plugins: {
42
+ 'your-plugin': yourPlugin,
43
+ },
44
+ rules: {
45
+ 'your-plugin/rule-name': 'error'
46
+ },
41
47
  }
42
- ];
48
+ ]);
43
49
  ```
44
50
 
45
51
  See [Using a Shareable Config](https://eslint.org/docs/latest/extend/shareable-configs#using-a-shareable-config) for more information.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-config-uphold",
3
- "version": "6.2.0",
3
+ "version": "6.3.0",
4
4
  "description": "Uphold-flavored ESLint config",
5
5
  "keywords": [
6
6
  "config",
@@ -33,15 +33,14 @@
33
33
  "dependencies": {
34
34
  "@babel/core": "^7.26.10",
35
35
  "@babel/eslint-parser": "^7.26.10",
36
- "@eslint/js": "^9.22.0",
36
+ "@eslint/js": "^9.23.0",
37
37
  "@stylistic/eslint-plugin-js": "4.2.0",
38
38
  "eslint-config-prettier": "^10.1.1",
39
- "eslint-plugin-jsdoc": "^50.6.8",
39
+ "eslint-plugin-jsdoc": "^50.6.9",
40
40
  "eslint-plugin-mocha": "^10.5.0",
41
41
  "eslint-plugin-n": "^17.16.2",
42
- "eslint-plugin-prettier": "^5.2.3",
42
+ "eslint-plugin-prettier": "^5.2.4",
43
43
  "eslint-plugin-promise": "^7.2.1",
44
- "eslint-plugin-rulesdir": "^0.2.2",
45
44
  "eslint-plugin-sort-destructure-keys": "^2.0.0",
46
45
  "eslint-plugin-sort-imports-requires": "^2.0.0",
47
46
  "eslint-plugin-sort-keys-fix": "^1.1.2",
@@ -52,14 +51,14 @@
52
51
  "@fastify/pre-commit": "^2.2.0",
53
52
  "@types/eslint": "^9.6.1",
54
53
  "@uphold/github-changelog-generator": "^4.0.2",
55
- "eslint": "^9.22.0",
54
+ "eslint": "^9.23.0",
56
55
  "mocha": "^11.1.0",
57
56
  "prettier": "^3.5.3",
58
57
  "release-it": "^18.1.2",
59
58
  "should": "^13.2.3"
60
59
  },
61
60
  "peerDependencies": {
62
- "eslint": "~9.22.0",
61
+ "eslint": "~9.23.0",
63
62
  "prettier": ">=3.0.0"
64
63
  },
65
64
  "peerDependenciesMeta": {
package/src/index.js CHANGED
@@ -1,9 +1,12 @@
1
+ 'use strict';
2
+
1
3
  /**
2
4
  * Module dependencies.
3
5
  *
4
6
  * @typedef {import('eslint').Linter.Config} LinterConfig
5
7
  */
6
8
 
9
+ const { defineConfig } = require('eslint/config');
7
10
  const babelParser = require('@babel/eslint-parser');
8
11
  const eslintPluginPrettierRecommended = require('eslint-plugin-prettier/recommended');
9
12
  const globals = require('globals');
@@ -11,26 +14,20 @@ const js = require('@eslint/js');
11
14
  const jsdoc = require('eslint-plugin-jsdoc');
12
15
  const mocha = require('eslint-plugin-mocha');
13
16
  const nodePlugin = require('eslint-plugin-n');
14
- const path = require('node:path');
15
17
  const promise = require('eslint-plugin-promise');
16
- const rulesDir = require('eslint-plugin-rulesdir');
18
+ const rules = require('./rules');
17
19
  const sortDestructureKeys = require('eslint-plugin-sort-destructure-keys');
18
20
  const sortImportsRequires = require('eslint-plugin-sort-imports-requires');
19
21
  const sortKeysFix = require('eslint-plugin-sort-keys-fix');
20
22
  const sqlTemplate = require('eslint-plugin-sql-template');
21
23
  const stylistic = require('@stylistic/eslint-plugin-js');
22
24
 
23
- /**
24
- * Configure the `rulesDir` plugin.
25
- */
26
-
27
- rulesDir.RULES_DIR = path.join(__dirname, 'rules');
28
-
29
25
  /**
30
26
  * Language options.
31
27
  *
32
28
  * @type {LinterConfig['languageOptions']}
33
29
  */
30
+
34
31
  const languageOptions = {
35
32
  ecmaVersion: 2020,
36
33
  globals: {
@@ -48,183 +45,193 @@ const languageOptions = {
48
45
  /**
49
46
  * Base configuration for Uphold.
50
47
  *
51
- * @type {LinterConfig}
48
+ * @type {LinterConfig[]}
52
49
  */
53
- const upholdBaseConfig = {
54
- languageOptions,
55
- plugins: {
56
- jsdoc,
57
- mocha,
58
- 'node-plugin': nodePlugin,
59
- promise,
60
- rulesdir: rulesDir,
61
- 'sort-destructure-keys': sortDestructureKeys,
62
- 'sort-imports-requires': sortImportsRequires,
63
- 'sort-keys-fix': sortKeysFix,
64
- 'sql-template': sqlTemplate,
65
- stylistic
66
- },
67
- rules: {
68
- ...js.configs.recommended.rules,
69
- 'accessor-pairs': 'error',
70
- 'array-callback-return': 'error',
71
- 'block-scoped-var': 'error',
72
- 'consistent-this': ['error', 'self'],
73
- curly: 'error',
74
- 'default-case': 'error',
75
- 'dot-notation': 'error',
76
- eqeqeq: ['error', 'smart'],
77
- 'func-style': ['error', 'declaration', { allowArrowFunctions: true }],
78
- 'id-length': ['error', { exceptions: ['_', 'e', 'i'] }],
79
- 'id-match': [
80
- 'error',
81
- '^_$|^[$_a-zA-Z]*[_a-zA-Z0-9]*[a-zA-Z0-9]*$|^[A-Z][_A-Z0-9]+[A-Z0-9]$',
82
- {
83
- onlyDeclarations: true,
84
- properties: true
85
- }
86
- ],
87
- 'jsdoc/no-defaults': 0,
88
- 'jsdoc/require-description-complete-sentence': 'error',
89
- 'jsdoc/require-jsdoc': 0,
90
- 'jsdoc/tag-lines': 0,
91
- 'max-depth': 'error',
92
- 'max-params': ['error', 4],
93
- 'mocha/no-exclusive-tests': 'error',
94
- 'mocha/no-identical-title': 'error',
95
- 'mocha/no-nested-tests': 'error',
96
- 'mocha/no-sibling-hooks': 'error',
97
- 'new-cap': 'error',
98
- 'no-alert': 'error',
99
- 'no-array-constructor': 'error',
100
- 'no-bitwise': 'error',
101
- 'no-caller': 'error',
102
- 'no-cond-assign': ['error', 'always'],
103
- 'no-console': 'warn',
104
- 'no-div-regex': 'error',
105
- 'no-dupe-keys': 'error',
106
- 'no-duplicate-imports': 'error',
107
- 'no-else-return': 'error',
108
- 'no-eq-null': 'error',
109
- 'no-eval': 'error',
110
- 'no-extend-native': 'error',
111
- 'no-extra-bind': 'error',
112
- 'no-implied-eval': 'error',
113
- 'no-inline-comments': 'error',
114
- 'no-irregular-whitespace': ['error', { skipComments: false, skipStrings: false, skipTemplates: false }],
115
- 'no-iterator': 'error',
116
- 'no-labels': 'error',
117
- 'no-lone-blocks': 'error',
118
- 'no-lonely-if': 'error',
119
- 'no-loop-func': 'error',
120
- 'no-multi-str': 'error',
121
- 'no-nested-ternary': 'error',
122
- 'no-new': 'error',
123
- 'no-new-func': 'error',
124
- 'no-new-wrappers': 'error',
125
- 'no-object-constructor': 'error',
126
- 'no-octal-escape': 'error',
127
- 'no-proto': 'error',
128
- 'no-return-assign': 'error',
129
- 'no-script-url': 'error',
130
- 'no-self-compare': 'error',
131
- 'no-sequences': 'error',
132
- 'no-throw-literal': 'error',
133
- 'no-undef-init': 'error',
134
- 'no-underscore-dangle': 'error',
135
- 'no-unneeded-ternary': 'error',
136
- 'no-unused-expressions': 'error',
137
- 'no-unused-vars': ['error', { caughtErrors: 'none' }],
138
- 'no-use-before-define': 'error',
139
- 'no-useless-call': 'error',
140
- 'no-useless-concat': 'error',
141
- 'no-var': 'error',
142
- 'no-void': 'error',
143
- 'node-plugin/no-mixed-requires': 'error',
144
- 'node-plugin/no-new-require': 'error',
145
- 'node-plugin/no-path-concat': 'error',
146
- 'node-plugin/no-process-env': 'error',
147
- 'node-plugin/no-process-exit': 'error',
148
- 'node-plugin/no-restricted-import': 'error',
149
- 'node-plugin/no-restricted-require': 'error',
150
- 'node-plugin/no-sync': 'error',
151
- 'object-shorthand': 'error',
152
- 'operator-assignment': 'error',
153
- 'prefer-const': 'error',
154
- 'prefer-destructuring': [
155
- 'error',
156
- {
157
- AssignmentExpression: {
158
- array: false,
159
- object: false
160
- },
161
50
 
162
- VariableDeclarator: {
163
- array: true,
164
- object: true
51
+ const upholdBaseConfig = defineConfig([
52
+ {
53
+ extends: [js.configs.recommended, jsdoc.configs['flat/recommended-error'], eslintPluginPrettierRecommended],
54
+ languageOptions,
55
+ name: 'uphold/base',
56
+ plugins: {
57
+ jsdoc,
58
+ mocha,
59
+ 'node-plugin': nodePlugin,
60
+ promise,
61
+ 'sort-destructure-keys': sortDestructureKeys,
62
+ 'sort-imports-requires': sortImportsRequires,
63
+ 'sort-keys-fix': sortKeysFix,
64
+ 'sql-template': sqlTemplate,
65
+ stylistic,
66
+ 'uphold-plugin': { rules }
67
+ },
68
+ rules: {
69
+ 'accessor-pairs': 'error',
70
+ 'array-callback-return': 'error',
71
+ 'block-scoped-var': 'error',
72
+ 'consistent-this': ['error', 'self'],
73
+ curly: 'error',
74
+ 'default-case': 'error',
75
+ 'dot-notation': 'error',
76
+ eqeqeq: ['error', 'smart'],
77
+ 'func-style': ['error', 'declaration', { allowArrowFunctions: true }],
78
+ 'id-length': ['error', { exceptions: ['_', 'e', 'i'] }],
79
+ 'id-match': [
80
+ 'error',
81
+ '^_$|^[$_a-zA-Z]*[_a-zA-Z0-9]*[a-zA-Z0-9]*$|^[A-Z][_A-Z0-9]+[A-Z0-9]$',
82
+ {
83
+ onlyDeclarations: true,
84
+ properties: true
165
85
  }
166
- },
167
- {
168
- enforceForRenamedProperties: false
169
- }
170
- ],
171
- 'prefer-spread': 'error',
172
- 'prefer-template': 'error',
173
- 'prettier/prettier': [
174
- 'error',
175
- {
176
- arrowParens: 'avoid',
177
- printWidth: 120,
178
- singleQuote: true,
179
- trailingComma: 'none'
180
- }
181
- ],
182
- 'promise/prefer-await-to-then': 'error',
183
- radix: 'error',
184
- 'require-atomic-updates': 'off',
185
- 'require-await': 'error',
186
- 'rulesdir/explicit-sinon-use-fake-timers': 'error',
187
- 'sort-destructure-keys/sort-destructure-keys': 'error',
188
- 'sort-imports-requires/sort-imports': ['error', { unsafeAutofix: true, useOldSingleMemberSyntax: true }],
189
- 'sort-imports-requires/sort-requires': [
190
- 'error',
191
- { unsafeAutofix: true, useAliases: false, useOldSingleMemberSyntax: true }
192
- ],
193
- 'sort-keys-fix/sort-keys-fix': ['error', 'asc', { natural: true }],
194
- 'sql-template/no-unsafe-query': 'error',
195
- 'stylistic/no-tabs': ['error', { allowIndentationTabs: true }],
196
- 'stylistic/padding-line-between-statements': [
197
- 'error',
198
- {
199
- blankLine: 'always',
200
- next: 'return',
201
- prev: '*'
202
- },
203
- {
204
- blankLine: 'always',
205
- next: '*',
206
- prev: ['const', 'let', 'var']
207
- },
208
- {
209
- blankLine: 'any',
210
- next: ['const', 'let', 'var'],
211
- prev: ['const', 'let', 'var']
212
- }
213
- ],
214
- 'stylistic/spaced-comment': 'error',
215
- 'vars-on-top': 'error',
216
- yoda: 'error'
86
+ ],
87
+ 'jsdoc/no-defaults': 0,
88
+ 'jsdoc/require-description-complete-sentence': 'error',
89
+ 'jsdoc/require-jsdoc': 0,
90
+ 'jsdoc/tag-lines': 0,
91
+ 'max-depth': 'error',
92
+ 'max-params': ['error', 4],
93
+ 'mocha/no-exclusive-tests': 'error',
94
+ 'mocha/no-identical-title': 'error',
95
+ 'mocha/no-nested-tests': 'error',
96
+ 'mocha/no-sibling-hooks': 'error',
97
+ 'new-cap': 'error',
98
+ 'no-alert': 'error',
99
+ 'no-array-constructor': 'error',
100
+ 'no-bitwise': 'error',
101
+ 'no-caller': 'error',
102
+ 'no-cond-assign': ['error', 'always'],
103
+ 'no-console': 'warn',
104
+ 'no-div-regex': 'error',
105
+ 'no-dupe-keys': 'error',
106
+ 'no-duplicate-imports': 'error',
107
+ 'no-else-return': 'error',
108
+ 'no-eq-null': 'error',
109
+ 'no-eval': 'error',
110
+ 'no-extend-native': 'error',
111
+ 'no-extra-bind': 'error',
112
+ 'no-implied-eval': 'error',
113
+ 'no-inline-comments': 'error',
114
+ 'no-irregular-whitespace': ['error', { skipComments: false, skipStrings: false, skipTemplates: false }],
115
+ 'no-iterator': 'error',
116
+ 'no-labels': 'error',
117
+ 'no-lone-blocks': 'error',
118
+ 'no-lonely-if': 'error',
119
+ 'no-loop-func': 'error',
120
+ 'no-multi-str': 'error',
121
+ 'no-nested-ternary': 'error',
122
+ 'no-new': 'error',
123
+ 'no-new-func': 'error',
124
+ 'no-new-wrappers': 'error',
125
+ 'no-object-constructor': 'error',
126
+ 'no-octal-escape': 'error',
127
+ 'no-proto': 'error',
128
+ 'no-return-assign': 'error',
129
+ 'no-script-url': 'error',
130
+ 'no-self-compare': 'error',
131
+ 'no-sequences': 'error',
132
+ 'no-throw-literal': 'error',
133
+ 'no-undef-init': 'error',
134
+ 'no-underscore-dangle': 'error',
135
+ 'no-unneeded-ternary': 'error',
136
+ 'no-unused-expressions': 'error',
137
+ 'no-unused-vars': ['error', { caughtErrors: 'none' }],
138
+ 'no-use-before-define': 'error',
139
+ 'no-useless-call': 'error',
140
+ 'no-useless-concat': 'error',
141
+ 'no-var': 'error',
142
+ 'no-void': 'error',
143
+ 'node-plugin/no-mixed-requires': 'error',
144
+ 'node-plugin/no-new-require': 'error',
145
+ 'node-plugin/no-path-concat': 'error',
146
+ 'node-plugin/no-process-env': 'error',
147
+ 'node-plugin/no-process-exit': 'error',
148
+ 'node-plugin/no-restricted-import': 'error',
149
+ 'node-plugin/no-restricted-require': 'error',
150
+ 'node-plugin/no-sync': 'error',
151
+ 'object-shorthand': 'error',
152
+ 'operator-assignment': 'error',
153
+ 'prefer-const': 'error',
154
+ 'prefer-destructuring': [
155
+ 'error',
156
+ {
157
+ AssignmentExpression: {
158
+ array: false,
159
+ object: false
160
+ },
161
+
162
+ VariableDeclarator: {
163
+ array: true,
164
+ object: true
165
+ }
166
+ },
167
+ {
168
+ enforceForRenamedProperties: false
169
+ }
170
+ ],
171
+ 'prefer-spread': 'error',
172
+ 'prefer-template': 'error',
173
+ 'prettier/prettier': [
174
+ 'error',
175
+ {
176
+ arrowParens: 'avoid',
177
+ printWidth: 120,
178
+ singleQuote: true,
179
+ trailingComma: 'none'
180
+ }
181
+ ],
182
+ 'promise/prefer-await-to-then': 'error',
183
+ radix: 'error',
184
+ 'require-atomic-updates': 'off',
185
+ 'require-await': 'error',
186
+ 'sort-destructure-keys/sort-destructure-keys': 'error',
187
+ 'sort-imports-requires/sort-imports': ['error', { unsafeAutofix: true, useOldSingleMemberSyntax: true }],
188
+ 'sort-imports-requires/sort-requires': [
189
+ 'error',
190
+ {
191
+ unsafeAutofix: true,
192
+ useAliases: false,
193
+ useOldSingleMemberSyntax: true
194
+ }
195
+ ],
196
+ 'sort-keys-fix/sort-keys-fix': ['error', 'asc', { natural: true }],
197
+ 'sql-template/no-unsafe-query': 'error',
198
+ 'stylistic/no-tabs': ['error', { allowIndentationTabs: true }],
199
+ 'stylistic/padding-line-between-statements': [
200
+ 'error',
201
+ {
202
+ blankLine: 'always',
203
+ next: 'return',
204
+ prev: '*'
205
+ },
206
+ {
207
+ blankLine: 'always',
208
+ next: '*',
209
+ prev: ['const', 'let', 'var']
210
+ },
211
+ {
212
+ blankLine: 'any',
213
+ next: ['const', 'let', 'var'],
214
+ prev: ['const', 'let', 'var']
215
+ }
216
+ ],
217
+ 'stylistic/spaced-comment': 'error',
218
+ 'uphold-plugin/explicit-sinon-use-fake-timers': 'error',
219
+ 'vars-on-top': 'error',
220
+ yoda: 'error'
221
+ }
217
222
  }
218
- };
223
+ ]);
219
224
 
220
225
  /**
221
226
  * Configuration for bin and scripts files.
222
227
  *
223
228
  * @type {LinterConfig}
224
229
  */
230
+
225
231
  const upholdBinScriptsConfig = {
226
232
  files: ['**/bin/**', '**/scripts/**'],
227
233
  languageOptions,
234
+ name: 'uphold/scripts',
228
235
  rules: {
229
236
  'no-console': 'off',
230
237
  'node-plugin/no-process-exit': 'off'
@@ -236,9 +243,11 @@ const upholdBinScriptsConfig = {
236
243
  *
237
244
  * @type {LinterConfig[]}
238
245
  */
239
- module.exports = [
240
- jsdoc.configs['flat/recommended-error'],
241
- eslintPluginPrettierRecommended,
242
- upholdBaseConfig,
243
- upholdBinScriptsConfig
244
- ];
246
+
247
+ module.exports = defineConfig([
248
+ {
249
+ extends: [upholdBaseConfig, upholdBinScriptsConfig],
250
+ languageOptions,
251
+ name: 'uphold/default'
252
+ }
253
+ ]);
@@ -1,16 +1,13 @@
1
1
  'use strict';
2
2
 
3
- // ------------------------------------------------------------------------------
4
- // Validates that `sinon.useFakeTimers()` is always called with an explicit `toFake` property.
5
- // ------------------------------------------------------------------------------
3
+ /**
4
+ * Export `explicit-sinon-use-fake-timers` rule.
5
+ * - Validates that `sinon.useFakeTimers()` is always called with an explicit `toFake` property.
6
+ *
7
+ * @type {import('eslint').Rule.RuleModule}
8
+ */
6
9
 
7
10
  module.exports = {
8
- meta: {
9
- messages: {
10
- avoidName: 'Calls to `sinon.useFakeTimers()` must provide a `toFake` configuration'
11
- }
12
- },
13
- // eslint-disable-next-line sort-keys-fix/sort-keys-fix
14
11
  create(context) {
15
12
  return {
16
13
  CallExpression(node) {
@@ -18,33 +15,41 @@ module.exports = {
18
15
  return;
19
16
  }
20
17
 
21
- if (node.callee.object.name === 'sinon' && node.callee.property.name === 'useFakeTimers') {
22
- if (!node.arguments.length) {
23
- context.report({
24
- message: 'Must pass an object with `toFake` configuration',
25
- node
26
- });
18
+ const isCalleeSinonUseFakeTimers =
19
+ node.callee.object.name === 'sinon' && node.callee.property.name === 'useFakeTimers';
20
+
21
+ if (!isCalleeSinonUseFakeTimers) {
22
+ return;
23
+ }
24
+
25
+ if (!node.arguments.length) {
26
+ context.report({ messageId: 'mustPassObject', node });
27
+ }
28
+
29
+ for (const argument of node.arguments) {
30
+ const isArgumentObjectExpression = argument.type === 'ObjectExpression';
31
+
32
+ if (!isArgumentObjectExpression) {
33
+ context.report({ messageId: 'notAnObject', node });
27
34
  }
28
35
 
29
- for (const argument of node.arguments) {
30
- if (argument.type === 'ObjectExpression') {
31
- if (!argument.properties.find(({ key: { name } }) => name === 'toFake')) {
32
- context.report({
33
- message: 'Object must contain `toFake` configuration',
34
- node
35
- });
36
- }
37
-
38
- continue;
39
- }
40
-
41
- context.report({
42
- message: 'Not an object',
43
- node
44
- });
36
+ if (!argument.properties.find(({ key }) => key && key.name === 'toFake')) {
37
+ context.report({ messageId: 'objectMustContainToFake', node });
45
38
  }
46
39
  }
47
40
  }
48
41
  };
42
+ },
43
+ meta: {
44
+ docs: {
45
+ description:
46
+ 'Calls to `sinon.useFakeTimers()` must provide a `toFake` configuration. (e.g. `sinon.useFakeTimers({ toFake: ["Date"] })`)'
47
+ },
48
+ messages: {
49
+ mustPassObject: 'Must pass an object with `toFake` configuration',
50
+ notAnObject: 'Not an object',
51
+ objectMustContainToFake: 'Object must contain `toFake` configuration'
52
+ },
53
+ type: 'problem'
49
54
  }
50
55
  };
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Export `rules`.
5
+ *
6
+ * @type {Record<string, import('eslint').Rule.RuleModule>}
7
+ */
8
+
9
+ module.exports = {
10
+ 'explicit-sinon-use-fake-timers': require('./explicit-sinon-use-fake-timers.js')
11
+ };