Skip to content

Commit 357010e

Browse files
committed
impl
1 parent deeb4e0 commit 357010e

File tree

7 files changed

+49
-65
lines changed

7 files changed

+49
-65
lines changed

specification/logstash/_types/Pipeline.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export class Pipeline {
6868
* The configuration for the pipeline.
6969
* @ext_doc_id logstash-configuration-file-structure
7070
*/
71+
// eslint-disable-next-line es-spec-validator/no-same-name-as-enclosing-type
7172
pipeline: string
7273
/**
7374
* Optional metadata about the pipeline, which can have any contents.

specification/ml/put_trained_model/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,5 +106,6 @@ export class AggregateOutput {
106106
}
107107

108108
export class Weights {
109+
// eslint-disable-next-line es-spec-validator/no-same-name-as-enclosing-type
109110
weights: double
110111
}

specification/nodes/_types/Stats.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,7 @@ export class Scripting {
10731073
}
10741074

10751075
export class Context {
1076+
// eslint-disable-next-line es-spec-validator/no-same-name-as-enclosing-type
10761077
context?: string
10771078
compilations?: long
10781079
cache_evictions?: long

specification/security/put_privileges/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import { Metadata, Name } from '@_types/common'
2121

2222
export class Actions {
23+
// eslint-disable-next-line es-spec-validator/no-same-name-as-enclosing-type
2324
actions: string[]
2425
application?: string
2526
name?: Name

validator/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ It is configured [in the specification directory](../specification/eslint.config
1010
| `single-key-dictionary-key-is-string` | `SingleKeyDictionary` keys must be strings. |
1111
| `dictionary-key-is-string` | `Dictionary` keys must be strings. |
1212
| `no-native-types` | TypeScript native utility types (`Record`, `Partial`, etc.) and collection types (`Map`, `Set`, etc.) are not allowed. Use spec-defined aliases like `Dictionary` instead. |
13-
| `no-same-name-as-enclosing-type` | TODO |
13+
| `no-same-name-as-enclosing-type` | Classes having fields with the same name as the class is breaking for some client libraries. |
1414
| `invalid-node-types` | The spec uses a subset of TypeScript, so some types, clauses and expressions are not allowed. |
1515
| `no-generic-number` | Generic `number` type is not allowed outside of `_types/Numeric.ts`. Use concrete numeric types like `integer`, `long`, `float`, `double`, etc. |
1616
| `request-must-have-urls` | All Request interfaces extending `RequestBase` must have a `urls` property defining their endpoint paths and HTTP methods. |

validator/rules/no-same-name-as-enclosing-type.js

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,47 +17,51 @@
1717
* under the License.
1818
*/
1919
import { ESLintUtils } from '@typescript-eslint/utils';
20+
import ts from "typescript";
2021

2122
const createRule = ESLintUtils.RuleCreator(name => `https://example.com/rule/${name}`)
2223

23-
const TYPE_SUGGESTIONS = {
24-
'Record': 'Use Dictionary instead',
25-
'Partial': 'Use spec-defined aliases instead',
26-
'Required': 'Use spec-defined aliases instead',
27-
'Pick': 'Use spec-defined aliases instead',
28-
'Omit': 'Use spec-defined aliases instead',
29-
'Map': 'Use Dictionary instead',
30-
'Set': 'Use an array type instead (e.g., string[])',
31-
'WeakMap': 'Use Dictionary instead',
32-
'WeakSet': 'Use an array type instead',
33-
};
34-
3524
export default createRule({
3625
name: 'no-same-name-as-enclosing-type',
3726
create(context) {
3827
return {
39-
TSTypeReference(node) {
40-
console.log("BBBBBBBBBBB")
41-
const typeName = node.typeName.name;
42-
if (TYPE_SUGGESTIONS[typeName]) {
43-
context.report({
44-
node,
45-
messageId: 'noNativeType',
46-
data: {
47-
type: typeName,
48-
suggestion: TYPE_SUGGESTIONS[typeName]
28+
ClassDeclaration(node) {
29+
if (!node.id || !node.id.name) {
30+
return; // anonymous class - nothing to check
31+
}
32+
const services = ESLintUtils.getParserServices(context)
33+
const tsClass = services.esTreeNodeToTSNodeMap.get(node);
34+
if (!tsClass || !tsClass.members) {
35+
return; // no fields
36+
}
37+
const className = node.id.name;
38+
for (const member of tsClass.members) {
39+
// Property declarations on the class (instance or static fields)
40+
if (ts.isPropertyDeclaration(member) || ts.isPropertySignature?.(member)) {
41+
const name = member.name;
42+
if (name && name.kind === ts.SyntaxKind.Identifier) {
43+
if (String(name.escapedText).toUpperCase() === className.toUpperCase()) {
44+
context.report({
45+
node,
46+
messageId: 'shouldNotUseClassNameForFieldNames',
47+
data: {
48+
class: className,
49+
suggestion: 'Fields in a class should not have the same name as the class itself.'
50+
}
51+
})
52+
}
53+
}
4954
}
50-
})
5155
}
5256
},
5357
}
5458
},
5559
meta: {
5660
docs: {
57-
description: 'TypeScript native utility and collection types not allowed, use spec-defined aliases',
61+
description: 'Classes having fields with the same name as the class is breaking for some client libraries.',
5862
},
5963
messages: {
60-
noNativeType: 'Native TypeScript type "{{type}}" is not allowed. {{suggestion}}.'
64+
shouldNotUseClassNameForFieldNames: 'Class "{{class}}" has invalid fields. {{suggestion}}.'
6165
},
6266
type: 'suggestion',
6367
},

validator/test/no-same-name-as-enclosing-type.js

Lines changed: 15 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -32,51 +32,27 @@ const ruleTester = new RuleTester({
3232

3333
ruleTester.run('no-same-name-as-enclosing-type', rule, {
3434
valid: [
35-
`type MyDict = Dictionary<string, object>`,
36-
`type MyMapping = Dictionary<string, any>`,
37-
`type MyType = { field: string }`,
38-
`class MyClass { prop: integer }`,
35+
`class MyClass {
36+
field: integer
37+
anotherfield: string
38+
}`,
3939
],
4040
invalid: [
4141
{
42-
code: `type MyRecord = Record<string, object>`,
43-
errors: [{ messageId: 'noNativeType' }]
42+
code: `class MyClass { MyClass: integer }`,
43+
errors: [{ messageId: 'shouldNotUseClassNameForFieldNames' }]
4444
},
4545
{
46-
code: `type MyPart = Partial<SomeType>`,
47-
errors: [{ messageId: 'noNativeType' }]
46+
code: `class MyClass { myclass: integer }`,
47+
errors: [{ messageId: 'shouldNotUseClassNameForFieldNames' }]
4848
},
4949
{
50-
code: `type MyReq = Required<SomeType>`,
51-
errors: [{ messageId: 'noNativeType' }]
52-
},
53-
{
54-
code: `type MyPick = Pick<SomeType, "field">`,
55-
errors: [{ messageId: 'noNativeType' }]
56-
},
57-
{
58-
code: `type MyOmit = Omit<SomeType, "field">`,
59-
errors: [{ messageId: 'noNativeType' }]
60-
},
61-
{
62-
code: `type MyMap = Map<string, object>`,
63-
errors: [{ messageId: 'noNativeType' }]
64-
},
65-
{
66-
code: `type MySet = Set<string>`,
67-
errors: [{ messageId: 'noNativeType' }]
68-
},
69-
{
70-
code: `type MyWeakMap = WeakMap<object, string>`,
71-
errors: [{ messageId: 'noNativeType' }]
72-
},
73-
{
74-
code: `type MyWeakSet = WeakSet<object>`,
75-
errors: [{ messageId: 'noNativeType' }]
76-
},
77-
{
78-
code: `class MyClass { items: Map<string, number> }`,
79-
errors: [{ messageId: 'noNativeType' }]
80-
},
50+
code: `class MyClass {
51+
field: integer
52+
anotherfield: string
53+
myclass: boolean
54+
}`,
55+
errors: [{ messageId: 'shouldNotUseClassNameForFieldNames' }]
56+
}
8157
],
8258
})

0 commit comments

Comments
 (0)