Skip to content

Commit d2189d0

Browse files
committed
WIP
1 parent 9f488b4 commit d2189d0

File tree

3 files changed

+106
-1
lines changed

3 files changed

+106
-1
lines changed

dprint.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"packages/**/docs"
2626
],
2727
"plugins": [
28-
"https://plugins.dprint.dev/typescript-0.95.11.wasm",
28+
"https://plugins.dprint.dev/typescript-0.95.12.wasm",
2929
"https://plugins.dprint.dev/json-0.21.0.wasm",
3030
"https://plugins.dprint.dev/markdown-0.20.0.wasm",
3131
"https://plugins.dprint.dev/toml-0.7.0.wasm",
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import tsx from "dedent";
2+
3+
import { allValid, ruleTester } from "../../../../../test";
4+
import rule, { RULE_NAME } from "./jsx-dollar";
5+
6+
ruleTester.run(RULE_NAME, rule, {
7+
invalid: [
8+
{
9+
code: tsx`
10+
const App = (props) => {
11+
return <div>Hello \${props.name}</div>;
12+
};
13+
`,
14+
errors: [
15+
{
16+
messageId: "jsxDollar",
17+
suggestions: [
18+
{
19+
messageId: "removeDollarSign",
20+
output: tsx`
21+
const App = (props) => {
22+
return <div>Hello {props.name}</div>;
23+
};
24+
`,
25+
},
26+
],
27+
},
28+
],
29+
},
30+
],
31+
valid: [
32+
...allValid,
33+
tsx`
34+
const App = (props) => {
35+
return [<div key="1">1</div>]
36+
};
37+
`,
38+
tsx`
39+
const App = (props) => {
40+
return <div>Hello $</div>;
41+
};
42+
`,
43+
],
44+
});
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import * as AST from "@eslint-react/ast";
2+
import type { RuleContext, RuleFeature } from "@eslint-react/shared";
3+
import type { TSESTree } from "@typescript-eslint/types";
4+
import { AST_NODE_TYPES as T } from "@typescript-eslint/types";
5+
import type { RuleListener } from "@typescript-eslint/utils/ts-eslint";
6+
import type { CamelCase } from "string-ts";
7+
8+
import { createRule } from "../utils";
9+
10+
export const RULE_NAME = "jsx-dollar";
11+
12+
export const RULE_FEATURES = [] as const satisfies RuleFeature[];
13+
14+
export type MessageID = CamelCase<typeof RULE_NAME> | "removeDollarSign";
15+
16+
export default createRule<[], MessageID>({
17+
meta: {
18+
type: "problem",
19+
docs: {
20+
description: "Prevents dollar signs from being inserted as text nodes before expressions.",
21+
[Symbol.for("rule_features")]: RULE_FEATURES,
22+
},
23+
fixable: "code",
24+
hasSuggestions: true,
25+
messages: {
26+
jsxDollar:
27+
"Possible misused dollar sign in text node. If you want to explicitly display '$' character i.e. show price, you can use template literals.",
28+
removeDollarSign: "Remove the dollar sign '$' before the expression.",
29+
},
30+
schema: [],
31+
},
32+
name: RULE_NAME,
33+
create,
34+
defaultOptions: [],
35+
});
36+
37+
export function create(context: RuleContext<MessageID, []>): RuleListener {
38+
const visitorFunction = (node: TSESTree.JSXElement | TSESTree.JSXFragment) => {
39+
for (const [index, child] of node.children.entries()) {
40+
if (child.type !== T.JSXText) continue;
41+
if (!child.raw.endsWith("$")) continue;
42+
if (node.children[index + 1]?.type !== T.JSXExpressionContainer) continue;
43+
context.report({
44+
messageId: "jsxDollar",
45+
node: child,
46+
suggest: [
47+
{
48+
messageId: "removeDollarSign",
49+
fix(fixer) {
50+
return fixer.removeRange([child.range[1] - 1, child.range[1]]);
51+
},
52+
},
53+
],
54+
});
55+
}
56+
};
57+
return {
58+
JSXElement: visitorFunction,
59+
JSXFragment: visitorFunction,
60+
};
61+
}

0 commit comments

Comments
 (0)