Skip to content

Commit 7af4c37

Browse files
committed
feat: implement no-template-curly-in-string
1 parent 7ec4c92 commit 7af4c37

File tree

3 files changed

+103
-0
lines changed

3 files changed

+103
-0
lines changed

internal/config/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ import (
9595
"github.com/web-infra-dev/rslint/internal/rules/no_constant_condition"
9696
"github.com/web-infra-dev/rslint/internal/rules/no_constructor_return"
9797
"github.com/web-infra-dev/rslint/internal/rules/no_debugger"
98+
"github.com/web-infra-dev/rslint/internal/rules/no_template_curly_in_string"
9899
)
99100

100101
// RslintConfig represents the top-level configuration array
@@ -459,6 +460,7 @@ func registerAllCoreEslintRules() {
459460
GlobalRuleRegistry.Register("no-constant-condition", no_constant_condition.NoConstantConditionRule)
460461
GlobalRuleRegistry.Register("no-constructor-return", no_constructor_return.NoConstructorReturnRule)
461462
GlobalRuleRegistry.Register("no-debugger", no_debugger.NoDebuggerRule)
463+
GlobalRuleRegistry.Register("no-template-curly-in-string", no_template_curly_in_string.NoTemplateCurlyInString)
462464
}
463465

464466
// getAllTypeScriptEslintPluginRules returns all registered rules (for backward compatibility when no config is provided)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package no_template_curly_in_string
2+
3+
import (
4+
"regexp"
5+
6+
"github.com/microsoft/typescript-go/shim/ast"
7+
"github.com/web-infra-dev/rslint/internal/rule"
8+
)
9+
10+
// https://eslint.org/docs/latest/rules/no-template-curly-in-string
11+
var NoTemplateCurlyInString = rule.Rule{
12+
Name: "no-template-curly-in-string",
13+
Run: func(ctx rule.RuleContext, options any) rule.RuleListeners {
14+
regex := regexp.MustCompile(`\$\{[^}]+\}`)
15+
return rule.RuleListeners{
16+
ast.KindStringLiteral: func(node *ast.Node) {
17+
expr := node.AsStringLiteral()
18+
if regex.MatchString(expr.Text) {
19+
ctx.ReportNode(node, rule.RuleMessage{
20+
Id: "unexpectedTemplateExpression",
21+
Description: "Template literal placeholder syntax in regular strings is not allowed.",
22+
})
23+
}
24+
},
25+
}
26+
},
27+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package no_template_curly_in_string
2+
3+
import (
4+
"testing"
5+
6+
"github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/fixtures"
7+
"github.com/web-infra-dev/rslint/internal/rule_tester"
8+
)
9+
10+
func TestNoTemplateCurlyInString(t *testing.T) {
11+
rule_tester.RunRuleTester(
12+
fixtures.GetRootDir(),
13+
"tsconfig.json",
14+
t,
15+
&NoTemplateCurlyInString,
16+
// Valid cases - ported from ESLint
17+
[]rule_tester.ValidTestCase{
18+
{Code: "`Hello, ${name}`;"},
19+
{Code: "templateFunction`Hello, ${name}`;"},
20+
{Code: "`Hello, name`;"},
21+
{Code: "'Hello, name';"},
22+
{Code: "'Hello, ' + name;"},
23+
{Code: "`Hello, ${index + 1}`"},
24+
{Code: "`Hello, ${name + \" foo\"}`"},
25+
{Code: "`Hello, ${name || \"foo\"}`"},
26+
{Code: "`Hello, ${{foo: \"bar\"}.foo}`"},
27+
{Code: "'$2'"},
28+
{Code: "'${'"},
29+
{Code: "'$}'"},
30+
{Code: "'{foo}'"},
31+
{Code: `'{foo: \"bar\"}'`},
32+
{Code: "const number = 3"},
33+
},
34+
// Invalid cases - ported from ESLint
35+
[]rule_tester.InvalidTestCase{
36+
{
37+
Code: "'Hello, ${name}'",
38+
Errors: []rule_tester.InvalidTestCaseError{
39+
{MessageId: "unexpectedTemplateExpression", Line: 1, Column: 1},
40+
},
41+
},
42+
{
43+
Code: "'${greeting}, ${name}'",
44+
Errors: []rule_tester.InvalidTestCaseError{
45+
{MessageId: "unexpectedTemplateExpression", Line: 1, Column: 1},
46+
},
47+
},
48+
{
49+
Code: "'Hello, ${index + 1}'",
50+
Errors: []rule_tester.InvalidTestCaseError{
51+
{MessageId: "unexpectedTemplateExpression", Line: 1, Column: 1},
52+
},
53+
},
54+
{
55+
Code: "'Hello, ${name + \\\" foo\\\"}'",
56+
Errors: []rule_tester.InvalidTestCaseError{
57+
{MessageId: "unexpectedTemplateExpression", Line: 1, Column: 1},
58+
},
59+
},
60+
{
61+
Code: "'Hello, ${name || \\\"foo\\\"}'",
62+
Errors: []rule_tester.InvalidTestCaseError{
63+
{MessageId: "unexpectedTemplateExpression", Line: 1, Column: 1},
64+
},
65+
},
66+
{
67+
Code: "'Hello, ${{foo: \\\"bar\\\"}.foo}'",
68+
Errors: []rule_tester.InvalidTestCaseError{
69+
{MessageId: "unexpectedTemplateExpression", Line: 1, Column: 1},
70+
},
71+
},
72+
},
73+
)
74+
}

0 commit comments

Comments
 (0)