Skip to content

Commit 41f32bb

Browse files
sonar-nigel[bot]Vibe Botclaudefrancois-mora-sonarsource
authored
JS-1321 Fix S101 false positive: allow $ prefix in default naming convention (#6484)
Co-authored-by: Vibe Bot <vibe-bot@sonarsource.com> Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> Co-authored-by: Francois Mora <francois.mora@sonarsource.com>
1 parent b5b7de7 commit 41f32bb

3 files changed

Lines changed: 29 additions & 4 deletions

File tree

packages/jsts/src/rules/S101/config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ export const fields = [
2323
{
2424
field: 'format',
2525
description: 'Regular expression used to check the class names against.',
26-
default: '^[A-Z][a-zA-Z0-9]*$',
26+
default: String.raw`^\$?[A-Z][a-zA-Z0-9]*$`,
27+
customDefault: String.raw`^\\$?[A-Z][a-zA-Z0-9]*$`,
2728
},
2829
],
2930
] as const satisfies ESLintConfiguration;

packages/jsts/src/rules/S101/rule.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import * as meta from './generated-meta.js';
2525

2626
type ClassOrInterfaceDeclaration = TSESTree.ClassDeclaration | TSESTree.TSInterfaceDeclaration;
2727

28-
const DEFAULT_FORMAT = '^[A-Z][a-zA-Z0-9]*$';
28+
const DEFAULT_FORMAT = String.raw`^\$?[A-Z][a-zA-Z0-9]*$`;
2929
const messages = {
3030
renameClass: 'Rename {{symbolType}} "{{symbol}}" to match the regular expression {{format}}.',
3131
};

packages/jsts/src/rules/S101/unit.test.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { describe, it } from 'node:test';
2020

2121
const ruleTester = new NoTypeCheckingRuleTester();
2222

23-
const DEFAULT_FORMAT = '^[A-Z][a-zA-Z0-9]*$';
23+
const DEFAULT_FORMAT = '^\\$?[A-Z][a-zA-Z0-9]*$';
2424
const CUSTOM_FORMAT = '^[_A-Z][a-zA-Z0-9]*$';
2525

2626
describe('S101', () => {
@@ -30,7 +30,7 @@ describe('S101', () => {
3030
{
3131
code: `
3232
class MyClass {}
33-
var x = class y {} // Compliant, rule doesn't check class expressions
33+
var x = class y {} // Compliant: expressions not checked
3434
interface MyInterface {}
3535
`,
3636
options: [{ format: DEFAULT_FORMAT }],
@@ -43,6 +43,22 @@ describe('S101', () => {
4343
`,
4444
options: [{ format: CUSTOM_FORMAT }],
4545
},
46+
{
47+
// Compliant: $ prefix allowed by default
48+
code: `
49+
interface $ZodCheckDef {}
50+
interface $ZodCheckInternals<T> {}
51+
interface $ZodCheckLessThanDef extends $ZodCheckDef {}
52+
interface $ZodCheckLessThanInternals<T extends number> extends $ZodCheckInternals<T> {}
53+
`,
54+
},
55+
{
56+
// Compliant: $ prefix allowed by default
57+
code: `
58+
class $LocationShimProvider {}
59+
class $ServiceProvider {}
60+
`,
61+
},
4662
],
4763
invalid: [
4864
{
@@ -67,6 +83,14 @@ describe('S101', () => {
6783
},
6884
],
6985
},
86+
{
87+
code: `interface $my_interface {}`, // $ before snake_case still flagged
88+
errors: [
89+
{
90+
message: `Rename interface "$my_interface" to match the regular expression ${DEFAULT_FORMAT}.`,
91+
},
92+
],
93+
},
7094
{
7195
code: `class __MyClass {}`,
7296
options: [{ format: CUSTOM_FORMAT }],

0 commit comments

Comments
 (0)