@dmitryrechkin/eslint-standard 1.3.4 → 1.3.6

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/eslint.config.mjs CHANGED
@@ -8,6 +8,7 @@ import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort';
8
8
  import perfectionistPlugin from 'eslint-plugin-perfectionist';
9
9
  import jsdocIndentPlugin from './src/plugins/jsdoc-indent.mjs';
10
10
  import interfaceBracePlugin from './src/plugins/interface-brace.mjs';
11
+ import switchCaseBracePlugin from './src/plugins/switch-case-brace.mjs';
11
12
  import securityPlugin from 'eslint-plugin-security';
12
13
  import jsxA11yPlugin from 'eslint-plugin-jsx-a11y';
13
14
  import promisePlugin from 'eslint-plugin-promise';
@@ -48,6 +49,7 @@ export default function ({
48
49
  'perfectionist': perfectionistPlugin,
49
50
  'jsdoc-indent': jsdocIndentPlugin,
50
51
  'interface-brace': interfaceBracePlugin,
52
+ 'switch-case-brace': switchCaseBracePlugin,
51
53
  'security': securityPlugin,
52
54
  'jsx-a11y': jsxA11yPlugin,
53
55
  'promise': promisePlugin,
@@ -77,7 +79,8 @@ export default function ({
77
79
 
78
80
  // Original coding guidelines
79
81
  'brace-style': 'off', // Disabled in favor of @stylistic/brace-style
80
- '@stylistic/brace-style': ['error', 'allman', { allowSingleLine: true }],
82
+ '@stylistic/brace-style': ['error', 'allman', { allowSingleLine: false }],
83
+ '@stylistic/block-spacing': ['error', 'never'], // Enforce consistent spacing inside blocks
81
84
  indent: 'off', // Disabled to avoid conflicts with @stylistic/indent and our JSDoc plugin
82
85
  '@stylistic/indent': ['error', 'tab', { SwitchCase: 1 }],
83
86
  quotes: 'off', // Disabled in favor of @stylistic/quotes
@@ -181,6 +184,9 @@ export default function ({
181
184
 
182
185
  // Enhanced: Interface brace style
183
186
  'interface-brace/interface-brace-style': 'error',
187
+
188
+ // Enhanced: Switch case brace style - Allman style for case blocks
189
+ 'switch-case-brace/switch-case-brace-style': 'error',
184
190
 
185
191
  // Additional naming conventions based on coding standards
186
192
  '@typescript-eslint/naming-convention': [
@@ -794,6 +800,7 @@ export default function ({
794
800
  // Test file specific overrides
795
801
  {
796
802
  files: ['**/*.test.{js,jsx,ts,tsx}', '**/*.spec.{js,jsx,ts,tsx}', '**/tests/**/*.{js,jsx,ts,tsx}'],
803
+ ignores: ['**/tests/fixtures/**/*'], // Don't apply test overrides to fixture files
797
804
  rules: {
798
805
  // Disable function scoping rule for test helpers
799
806
  'unicorn/consistent-function-scoping': 'off',
@@ -807,9 +814,16 @@ export default function ({
807
814
  exceptions: ['id', 'fn']
808
815
  }],
809
816
 
810
- // Relax rules that are too strict for tests
811
- 'unicorn/no-null': 'warn', // APIs often legitimately use null
812
- 'functional/no-loop-statements': 'warn', // Loops can be clearer than functional alternatives in tests
817
+ // Disable rules inappropriate for test files
818
+ 'functional/no-loop-statements': 'off', // Loops are often clearer than functional alternatives in tests
819
+ 'functional/no-let': 'off', // Test setup requires mutable variables
820
+ 'functional/immutable-data': 'off', // Test mocking requires object mutations
821
+ 'security/detect-non-literal-fs-filename': 'off', // Tests legitimately need dynamic file paths
822
+ 'unicorn/prefer-module': 'off', // Tests may need __dirname for reliable paths
823
+
824
+ // Keep as warnings - still worth improving when possible
825
+ 'unicorn/no-null': 'off', // APIs often use null, but const can be better
826
+ 'sonarjs/no-duplicate-string': 'off', // Test strings repeat, but constants still help readability
813
827
  },
814
828
  },
815
829
  ];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dmitryrechkin/eslint-standard",
3
3
  "description": "This package provides a shared ESLint configuration which includes TypeScript support and a set of specific linting rules designed to ensure high-quality and consistent code style across projects.",
4
- "version": "1.3.4",
4
+ "version": "1.3.6",
5
5
  "main": "eslint.config.mjs",
6
6
  "bin": {
7
7
  "eslint-standard": "./src/cli/index.mjs"
@@ -24,6 +24,7 @@
24
24
  "test:security": "node tests/test-security-rules.js",
25
25
  "test:sonarjs": "node tests/test-sonarjs-rules.js",
26
26
  "test:unicorn": "node tests/test-unicorn-rules.js",
27
+ "test:switch-case": "node tests/test-switch-case-simple.js",
27
28
  "test:cli": "node tests/test-cli.js",
28
29
  "test:install": "node tests/test-install-simulation.js"
29
30
  },
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Custom ESLint plugin rule to enforce Allman-style brace placement for switch case blocks
3
+ * Forces case block opening braces to be on new lines
4
+ *
5
+ * Example:
6
+ * case 'VALUE':
7
+ * {
8
+ * // code here
9
+ * }
10
+ */
11
+
12
+ const switchCaseBraceRule = {
13
+ meta: {
14
+ type: 'layout',
15
+ docs: {
16
+ description: 'Enforce Allman-style brace placement for switch case blocks',
17
+ category: 'Stylistic Issues',
18
+ recommended: false
19
+ },
20
+ fixable: 'whitespace',
21
+ schema: [],
22
+ messages: {
23
+ expectedNewlineBeforeOpeningBrace: 'Expected a newline before opening brace in case block.',
24
+ expectedNewlineAfterOpeningBrace: 'Expected a newline after opening brace in case block.'
25
+ }
26
+ },
27
+
28
+ create(context) {
29
+ const sourceCode = context.getSourceCode();
30
+
31
+ /**
32
+ * Check if a case clause has a block statement and enforce proper brace placement
33
+ * @param {ASTNode} node - The SwitchCase node
34
+ */
35
+ function checkCaseClause(node) {
36
+ // Only process case clauses that have a single BlockStatement
37
+ if (node.consequent.length !== 1 || node.consequent[0].type !== 'BlockStatement') {
38
+ return;
39
+ }
40
+
41
+ const blockStatement = node.consequent[0];
42
+ const openingBrace = sourceCode.getFirstToken(blockStatement);
43
+ const closingBrace = sourceCode.getLastToken(blockStatement);
44
+
45
+ // Get the colon token after case label
46
+ const colonToken = sourceCode.getTokenAfter(node.test || sourceCode.getFirstToken(node));
47
+
48
+ // Check if opening brace is on the same line as the colon
49
+ if (colonToken.loc.end.line === openingBrace.loc.start.line) {
50
+ context.report({
51
+ node: blockStatement,
52
+ messageId: 'expectedNewlineBeforeOpeningBrace',
53
+ fix(fixer) {
54
+ // Add newline and proper indentation before opening brace
55
+ const indentation = '\t'.repeat(getIndentLevel(node) + 1);
56
+ return fixer.replaceTextRange(
57
+ [colonToken.range[1], openingBrace.range[0]],
58
+ `\n${indentation}`
59
+ );
60
+ }
61
+ });
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Get the indentation level for a node
67
+ * @param {ASTNode} node - The node to check
68
+ * @returns {number} The indentation level
69
+ */
70
+ function getIndentLevel(node) {
71
+ const line = sourceCode.lines[node.loc.start.line - 1];
72
+ const match = line.match(/^(\t*)/);
73
+ return match ? match[1].length : 0;
74
+ }
75
+
76
+ return {
77
+ SwitchCase: checkCaseClause
78
+ };
79
+ }
80
+ };
81
+
82
+ export default {
83
+ rules: {
84
+ 'switch-case-brace-style': switchCaseBraceRule
85
+ }
86
+ };