1
- function capitalizeFirstLetter ( string ) {
2
- return string . charAt ( 0 ) . toUpperCase ( ) + string . slice ( 1 ) ;
1
+ function convertToFunctionName ( name ) {
2
+ if ( name . startsWith ( 'on' ) ) {
3
+ return name . replace ( / ^ o n / , 'handle' ) ;
4
+ } else {
5
+ return `on${ name . charAt ( 0 ) . toUpperCase ( ) + name . slice ( 1 ) } ` ;
6
+ }
7
+ }
8
+
9
+ function invertKeyValues ( obj ) {
10
+ return Object . fromEntries (
11
+ Object . entries ( obj ) . map ( entry => entry . reverse ( ) )
12
+ ) ;
3
13
}
4
14
5
15
new Synvert . Rewriter ( "react" , "prevent-default" , ( ) => {
6
16
description ( `
7
- convert foo to bar
17
+ Force add preventDefault() to onClick event handler.
18
+
19
+ \`\`\`javascript
20
+ const Post = ({ newPost, doDelete }) => {
21
+ const deletePost = () => {
22
+ doDelete();
23
+ }
24
+
25
+ return (
26
+ <a href="#" onClick={newPost}>New</a>
27
+ <a href="#" onClick={deletePost}>Delete</a>
28
+ )
29
+ }
30
+ export default Post;
31
+ \`\`\`
32
+
33
+ =>
34
+
35
+ \`\`\`javascript
36
+ const Post = ({ newPost, doDelete }) => {
37
+ const deletePost = (event) => {
38
+ event.preventDefault();
39
+
40
+ doDelete();
41
+ }
42
+
43
+ const onNewPost = (event) => {
44
+ event.preventDefault();
45
+
46
+ newPost();
47
+ }
48
+
49
+ return (
50
+ <a href="#" onClick={onNewPost}>New</a>
51
+ <a href="#" onClick={deletePost}>Delete</a>
52
+ )
53
+ }
54
+ export default Post;
55
+ \`\`\`
8
56
` ) ;
9
57
10
58
configure ( { parser : Synvert . Parser . TYPESCRIPT } ) ;
@@ -16,6 +64,7 @@ new Synvert.Rewriter("react", "prevent-default", () => {
16
64
// { functionName: 'preventDefaultNotCalled' } the function is defined with event parameter but not call preventDefault();
17
65
// { functionName: 'preventDefaultCalled' } the function is defined with event parameter and call preventDefault();
18
66
const onClickPreventDefault = { } ;
67
+ const onClickCode = { } ;
19
68
20
69
// find a elements whose href attribute is '#'
21
70
findNode ( `
@@ -31,8 +80,17 @@ new Synvert.Rewriter("react", "prevent-default", () => {
31
80
]
32
81
[closingElement=.JsxClosingElement[tagName=a]]` ,
33
82
( ) => {
34
- findNode ( `.JsxAttribute[name=onClick]` , ( ) => {
83
+ findNode ( `.JsxAttribute[name=onClick][initializer=.JsxExpression[expression=.Identifier]] ` , ( ) => {
35
84
onClickPreventDefault [ this . currentNode . initializer . expression . escapedText ] = 'functionNotDefined' ;
85
+ onClickCode [ this . currentNode . initializer . expression . escapedText ] = this . mutationAdapter . getSource ( this . currentNode . initializer . expression ) + '()' ;
86
+ } ) ;
87
+ findNode ( `.JsxAttribute[name=onClick][initializer=.JsxExpression[expression=.ArrowFunction[body=.CallExpression]]]` , ( ) => {
88
+ onClickPreventDefault [ this . currentNode . initializer . expression . body . expression . escapedText ] = 'functionNotDefined' ;
89
+ onClickCode [ this . currentNode . initializer . expression . body . expression . escapedText ] = this . mutationAdapter . getSource ( this . currentNode . initializer . expression . body ) ;
90
+ } ) ;
91
+ findNode ( `.JsxAttribute[name=onClick][initializer=.JsxExpression[expression=.ArrowFunction[body=.Block[statements.length>0]]]]` , ( ) => {
92
+ onClickPreventDefault [ this . currentNode . initializer . expression . body . statements [ 0 ] . expression . expression . escapedText ] = 'functionNotDefined' ;
93
+ onClickCode [ this . currentNode . initializer . expression . body . statements [ 0 ] . expression . expression . escapedText ] = this . currentNode . initializer . expression . body . statements . map ( statement => this . mutationAdapter . getSource ( statement ) ) . join ( "\n" ) ;
36
94
} ) ;
37
95
}
38
96
) ;
@@ -66,18 +124,36 @@ new Synvert.Rewriter("react", "prevent-default", () => {
66
124
]
67
125
]
68
126
]
69
- [closingElement=.JsxClosingElement[tagName=a]] .JsxAttribute[name=onClick][initializer=.JsxExpression[expression= ${ functionName } ]] ` ,
127
+ [closingElement=.JsxClosingElement[tagName=a]]` ,
70
128
( ) => {
71
- replace ( 'initializer' , { with : `{on${ capitalizeFirstLetter ( functionName ) } }` } ) ;
129
+ findNode ( `
130
+ .JsxAttribute
131
+ [name=onClick]
132
+ [initializer=.JsxExpression
133
+ [expression IN (
134
+ ${ functionName }
135
+ .ArrowFunction
136
+ [body=.CallExpression
137
+ [expression=${ functionName } ]
138
+ ]
139
+ .ArrowFunction
140
+ [body=.Block
141
+ [statements.length>0]
142
+ [statements.0.expression.expression=${ functionName } ]
143
+ ]
144
+ )]
145
+ ]` , ( ) => {
146
+ replace ( 'initializer' , { with : `{${ convertToFunctionName ( functionName ) } }` } ) ;
147
+ } ) ;
72
148
}
73
149
) ;
74
150
75
- findNode ( `.ReturnStatement` , ( ) => {
151
+ findNode ( `.Block:first-child > . ReturnStatement` , ( ) => {
76
152
insertBefore ( `
77
- const on ${ capitalizeFirstLetter ( functionName ) } = (event) => {
153
+ const ${ convertToFunctionName ( functionName ) } = (event) => {
78
154
event.preventDefault();
79
155
80
- ${ functionName } () ;
156
+ ${ onClickCode [ functionName ] } ;
81
157
}
82
158
` . trim ( ) + "\n" , { fixIndent : true } ) ;
83
159
} ) ;
0 commit comments