Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import (
"github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/no_implied_eval"
"github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/no_invalid_void_type"
"github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/no_meaningless_void_operator"
"github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/no_misused_new"
"github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/no_misused_promises"
"github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/no_misused_spread"
"github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/no_mixed_enums"
Expand Down Expand Up @@ -391,6 +392,7 @@ func registerAllTypeScriptEslintPluginRules() {
GlobalRuleRegistry.Register("@typescript-eslint/no-for-in-array", no_for_in_array.NoForInArrayRule)
GlobalRuleRegistry.Register("@typescript-eslint/no-implied-eval", no_implied_eval.NoImpliedEvalRule)
GlobalRuleRegistry.Register("@typescript-eslint/no-meaningless-void-operator", no_meaningless_void_operator.NoMeaninglessVoidOperatorRule)
GlobalRuleRegistry.Register("@typescript-eslint/no-misused-new", no_misused_new.NoMisusedNewRule)
GlobalRuleRegistry.Register("@typescript-eslint/no-misused-promises", no_misused_promises.NoMisusedPromisesRule)
GlobalRuleRegistry.Register("@typescript-eslint/no-misused-spread", no_misused_spread.NoMisusedSpreadRule)
GlobalRuleRegistry.Register("@typescript-eslint/no-mixed-enums", no_mixed_enums.NoMixedEnumsRule)
Expand Down
74 changes: 74 additions & 0 deletions internal/plugins/typescript/rules/no_misused_new/no_misused_new.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package no_misused_new

import (
"github.com/microsoft/typescript-go/shim/ast"
"github.com/web-infra-dev/rslint/internal/rule"
)

/**
* check whether the name of the return type of the node is the same as the name of the parent node.
*/
func check(node *ast.Node) bool {
parentName := node.Parent.Name()
if parentName == nil {
return false
}

nodeType := node.Type()
if nodeType != nil && ast.IsTypeReferenceNode(nodeType) {
typeName := nodeType.AsTypeReference().TypeName
if ast.IsIdentifier(typeName) {
return typeName.Text() == parentName.Text()
}
}
return false
}

var NoMisusedNewRule = rule.CreateRule(rule.Rule{
Name: "no-misused-new",
Run: func(ctx rule.RuleContext, options any) rule.RuleListeners {
return rule.RuleListeners{
ast.KindMethodDeclaration: func(node *ast.Node) {
parentKind := node.Parent.Kind
if parentKind != ast.KindClassDeclaration && parentKind != ast.KindClassExpression {
return
}

if node.Name().Text() != "new" {
return
}
// If the function body exists, it's valid for this rule.
body := node.Body()
if body != nil {
return
}

if check(node) {
ctx.ReportNode(node, rule.RuleMessage{
Id: "errorMessageClass",
Description: "Class cannot have method named `new`.",
})
}
},
ast.KindConstructSignature: func(node *ast.Node) {
if node.Parent.Kind != ast.KindInterfaceDeclaration {
return
}
if check(node) {
ctx.ReportNode(node, rule.RuleMessage{
Id: "errorMessageInterface",
Description: "interfaces cannot be constructed, only classes.",
})
}
},
ast.KindMethodSignature: func(node *ast.Node) {
if node.Name().Text() == "constructor" {
ctx.ReportNode(node, rule.RuleMessage{
Id: "errorMessageInterface",
Description: "interfaces cannot be constructed, only classes.",
})
}
},
}
},
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package no_misused_new

import (
"testing"

"github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/fixtures"
"github.com/web-infra-dev/rslint/internal/rule_tester"
)

func TestNoMisusedNewRule(t *testing.T) {
rule_tester.RunRuleTester(fixtures.GetRootDir(), "tsconfig.json", t, &NoMisusedNewRule, []rule_tester.ValidTestCase{
{
Code: `
declare abstract class C {
foo() {}
get new();
bar();
}
`,
},
{
Code: `
class C {
constructor();
}
`,
},
{
Code: `
const foo = class {
constructor();
};
`,
},
{
Code: `
const foo = class {
new(): X;
};
`,
},
{
Code: `
class C {
constructor() {}
}
`,
},
{
Code: `
const foo = class {
new() {}
};
`,
},
{
Code: `
const foo = class {
constructor() {}
};
`,
},
{
Code: `
interface I {
new (): {};
}
`,
},
{
Code: `type T = { new (): T };`,
},
{
Code: `
export default class {
constructor();
}
`,
},
{
Code: `
interface foo {
new <T>(): bar<T>;
}
`,
},
{
Code: `
interface foo {
new <T>(): 'x';
}
`,
},
}, []rule_tester.InvalidTestCase{
{
Code: `
interface I {
new (): I;
constructor(): void;
}
`,
Errors: []rule_tester.InvalidTestCaseError{
{
MessageId: "errorMessageInterface",
Line: 3,
},
{
MessageId: "errorMessageInterface",
Line: 4,
},
},
},
{
Code: `
interface G {
new <T>(): G<T>;
}
`,
Errors: []rule_tester.InvalidTestCaseError{
{
MessageId: "errorMessageInterface",
},
},
},
{
Code: `
type T = {
constructor(): void;
};
`,
Errors: []rule_tester.InvalidTestCaseError{
{
MessageId: "errorMessageInterface",
},
},
},
{
Code: `
class C {
new(): C;
}
`,
Errors: []rule_tester.InvalidTestCaseError{
{
MessageId: "errorMessageClass",
},
},
},
{
Code: `
declare abstract class C {
new(): C;
}
`,
Errors: []rule_tester.InvalidTestCaseError{
{
MessageId: "errorMessageClass",
},
},
},
{
Code: `
interface I {
constructor(): '';
}
`,
Errors: []rule_tester.InvalidTestCaseError{
{
MessageId: "errorMessageInterface",
},
},
},
})
}
2 changes: 1 addition & 1 deletion packages/rslint-test-tools/rstest.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export default defineConfig({
// './tests/typescript-eslint/rules/no-loss-of-precision.test.ts',
// './tests/typescript-eslint/rules/no-magic-numbers.test.ts',
// './tests/typescript-eslint/rules/no-meaningless-void-operator.test.ts',
// './tests/typescript-eslint/rules/no-misused-new.test.ts',
'./tests/typescript-eslint/rules/no-misused-new.test.ts',
// './tests/typescript-eslint/rules/no-misused-promises.test.ts',
// './tests/typescript-eslint/rules/no-misused-spread.test.ts',
// './tests/typescript-eslint/rules/no-mixed-enums.test.ts',
Expand Down
Loading
Loading