@@ -4,26 +4,62 @@ const fs = require('fs');
4
4
const path = require ( 'path' ) ;
5
5
const parseUtils = require ( './parse' ) ;
6
6
7
+ const replaceCodeByRange = ( code , range , replaceValue ) => {
8
+
9
+ const lines = _ . split ( code , '\n' ) ;
10
+
11
+ const { startIndex, endIndex } = _ . reduce ( lines , ( res , line , index ) => {
12
+
13
+ if ( index < range . start . line ) {
14
+ res . startIndex = ( res . startIndex + _ . size ( line ) + 1 ) ;
15
+ }
16
+
17
+ if ( index === range . start . line ) {
18
+ res . startIndex += range . start . character ;
19
+ }
20
+
21
+ if ( index < range . end . line ) {
22
+ res . endIndex = ( res . endIndex + _ . size ( line ) + 1 ) ;
23
+ }
24
+
25
+ if ( index === range . end . line ) {
26
+ res . endIndex += range . end . character ;
27
+ }
28
+
29
+ return res ;
30
+
31
+ } , { startIndex : 0 , endIndex : 0 } ) ;
32
+
33
+ return `${ code . substring ( 0 , startIndex ) } ${ replaceValue } ${ code . substring ( endIndex ) } ` ;
34
+
35
+ } ;
36
+
7
37
const validateSelection = ( ) => {
8
38
9
39
const editor = vscode . window . activeTextEditor ;
10
40
const selection = editor . document . getText ( editor . selection ) ;
11
41
12
- try { parseUtils . transformCode ( `<>${ selection } </>` ) ; }
13
- catch { throw new Error ( 'Invalid selection. Make sure your selection represents a valid React component' ) ; }
42
+ try {
43
+ parseUtils . transformCode ( `<>${ selection } </>` ) ;
44
+ } catch {
45
+ throw new Error ( 'Invalid selection. Make sure your selection represents a valid React component' ) ;
46
+ }
14
47
15
48
const codeWithoutSelection = replaceCodeByRange ( editor . document . getText ( ) , editor . selection , '<></>' ) ;
16
49
17
- try { parseUtils . transformCode ( codeWithoutSelection ) ; }
18
- catch { throw new Error ( 'Invalid selection. Make sure the code remains valid without your selection' ) ; }
50
+ try {
51
+ parseUtils . transformCode ( codeWithoutSelection ) ;
52
+ } catch {
53
+ throw new Error ( 'Invalid selection. Make sure the code remains valid without your selection' ) ;
54
+ }
19
55
20
56
} ;
21
57
22
58
const buildComponentPath = name => {
23
59
24
60
const activeDocumentPath = vscode . window . activeTextEditor . document . uri . fsPath ;
25
- const activeDocumentExtension = activeDocumentPath . replace ( / ( .* ) + \. [ ^ \. ] + / , '$1' ) ;
26
- const nameWithoutExtension = name . replace ( / \. [ ^ \. ] + $ / , '' ) ;
61
+ const activeDocumentExtension = activeDocumentPath . replace ( / ( .* ) + \. [ ^ \\ . ] + / , '$1' ) ;
62
+ const nameWithoutExtension = name . replace ( / \. [ ^ \\ . ] + $ / , '' ) ;
27
63
28
64
return path . join ( activeDocumentPath , '..' , `${ nameWithoutExtension } .${ activeDocumentExtension } ` ) ;
29
65
@@ -46,36 +82,6 @@ const askForComponentName = async () => {
46
82
return name ;
47
83
} ;
48
84
49
- const replaceCodeByRange = ( code , range , replaceValue ) => {
50
-
51
- const lines = _ . split ( code , '\n' ) ;
52
-
53
- const { startIndex, endIndex } = _ . reduce ( lines , ( res , line , index ) => {
54
-
55
- if ( index < range . start . line ) {
56
- res . startIndex = ( res . startIndex + _ . size ( line ) + 1 ) ;
57
- }
58
-
59
- if ( index === range . start . line ) {
60
- res . startIndex = ( res . startIndex + range . start . character ) ;
61
- }
62
-
63
- if ( index < range . end . line ) {
64
- res . endIndex = ( res . endIndex + _ . size ( line ) + 1 ) ;
65
- }
66
-
67
- if ( index === range . end . line ) {
68
- res . endIndex = ( res . endIndex + range . end . character ) ;
69
- }
70
-
71
- return res ;
72
-
73
- } , { startIndex : 0 , endIndex : 0 } ) ;
74
-
75
- return `${ code . substring ( 0 , startIndex ) } ${ replaceValue } ${ code . substring ( endIndex ) } ` ;
76
-
77
- } ;
78
-
79
85
const getFullDocumentRange = document => new vscode . Range (
80
86
document . positionAt ( 0 ) ,
81
87
document . positionAt ( _ . size ( document . getText ( ) ) ) ,
@@ -89,7 +95,7 @@ const getFirstAndLastImportLineIndexes = codeLines => {
89
95
90
96
return { firstImportLineIndex, lastImportLineIndex} ;
91
97
92
- }
98
+ } ;
93
99
94
100
const replaceSelection = async ( { reactElement, name } ) => {
95
101
@@ -101,7 +107,7 @@ const replaceSelection = async ({ reactElement, name }) => {
101
107
await editor . edit ( edit => {
102
108
edit . replace ( editor . selection , reactElement ) ;
103
109
edit . insert ( new vscode . Position ( ( lastImportLineIndex + 1 ) , 0 ) , `import ${ name } from './${ name } ';\n` ) ;
104
- } ) ;
110
+ } ) ;
105
111
106
112
parseUtils . eslintAutofix ( document . getText ( ) , { filePath : document . uri . fsPath } )
107
113
. then ( output => {
@@ -128,7 +134,7 @@ const removeUnusedImports = async () => {
128
134
const usedImportsString = _ . join ( parseUtils . getUsedImports ( code ) , '\n' ) ;
129
135
const codeWithUsedImports = _ . replace ( code , importsString , usedImportsString ) ;
130
136
131
- await editor . edit ( edit => edit . replace ( getFullDocumentRange ( document ) , codeWithUsedImports ) ) ;
137
+ await editor . edit ( edit => edit . replace ( getFullDocumentRange ( document ) , codeWithUsedImports ) ) ;
132
138
133
139
parseUtils . eslintAutofix ( document . getText ( ) , { filePath : document . uri . fsPath } )
134
140
. then ( output => {
@@ -143,7 +149,6 @@ const removeUnusedImports = async () => {
143
149
144
150
} ;
145
151
146
-
147
152
const updateOriginalComponent = async ( { newComponent } ) => {
148
153
149
154
await replaceSelection ( newComponent ) ;
@@ -169,59 +174,67 @@ const generateReactElement = ({ name, props, jsx }) => {
169
174
return `${ leadingSpacesFromStart } <${ name } ${ propsString } />` ;
170
175
} ;
171
176
172
- const extractRelevantImportsAndProps = ( ) => {
173
-
174
- const editor = vscode . window . activeTextEditor ;
175
- const code = editor . document . getText ( ) ;
176
- const selection = editor . document . getText ( editor . selection ) ;
177
-
178
- const selectionAndImports = `
179
- ${ buildImportsString ( parseUtils . getImports ( code ) ) } \n
180
- export default () => (<>${ selection } </>);
181
- ` ;
182
-
183
- return {
184
- props : parseUtils . getUndefinedVars ( selectionAndImports ) ,
185
- imports : parseUtils . getUsedImports ( selectionAndImports ) ,
186
- } ;
187
-
188
- } ;
189
-
190
177
const buildImportsString = imports => _ . join ( imports , '\n' ) ;
191
178
192
179
const buildPropsString = props => {
193
180
194
181
const numberOfProps = _ . size ( props ) ;
195
182
196
- if ( numberOfProps > 2 ) { return `{\n ${ _ . join ( props , ` ,\n ` ) } ,\n}` ; }
183
+ if ( numberOfProps > 2 ) { return `{\n ${ _ . join ( props , ' ,\n ' ) } ,\n}` ; }
197
184
if ( numberOfProps === 2 ) { return `{${ _ . join ( props , ', ' ) } }` ; }
198
185
if ( numberOfProps === 1 ) { return `{${ props [ 0 ] } }` ; }
199
186
200
187
return '' ;
201
188
202
189
} ;
203
190
191
+ const extractRelevantImportsAndProps = ( ) => {
192
+
193
+ const editor = vscode . window . activeTextEditor ;
194
+ const code = editor . document . getText ( ) ;
195
+ const selection = editor . document . getText ( editor . selection ) ;
196
+
197
+ const selectionAndImports = `
198
+ ${ buildImportsString ( parseUtils . getImports ( code ) ) } \n
199
+ export default () => (<>${ selection } </>);
200
+ ` ;
201
+
202
+ return {
203
+ props : parseUtils . getUndefinedVars ( selectionAndImports ) ,
204
+ imports : parseUtils . getUsedImports ( selectionAndImports ) ,
205
+ } ;
206
+
207
+ } ;
208
+
204
209
const shouldWrapCodeWithEmptyTag = code => {
205
- try { parseUtils . transformCode ( code ) ; }
206
- catch { return true ; }
210
+ try {
211
+ parseUtils . transformCode ( code ) ;
212
+ } catch {
213
+ return true ;
214
+ }
207
215
} ;
208
216
209
217
const createNewComponent = async componentName => {
210
218
211
219
const editor = vscode . window . activeTextEditor ;
212
220
const selection = editor . document . getText ( editor . selection ) ;
213
221
const { imports, props } = extractRelevantImportsAndProps ( componentName ) ;
222
+
223
+ const importsString = buildImportsString ( imports ) ;
224
+ const propsString = buildPropsString ( props ) ;
225
+ const jsx = ( shouldWrapCodeWithEmptyTag ( selection ) ? `<>\n${ selection } \n</>` : selection ) ;
214
226
215
227
const newComponent = {
216
- code : parseUtils . pretify (
217
- ` ${ buildImportsString ( imports ) } \n\n` +
228
+ code : parseUtils . pretify ( _ . template (
229
+ `<%= importsString %>
218
230
219
- ` const ${ componentName } = (${ buildPropsString ( props ) } ) => (\n` +
220
- ` ${ shouldWrapCodeWithEmptyTag ( selection ) ? `<>\n ${ selection } \n</>` : selection } \n` +
221
- `);\n\n` +
231
+ const <%= componentName %> = (<%= propsString %>) => (
232
+ <%= jsx %>
233
+ );
222
234
223
- `export default ${ componentName } ;\n` ,
224
- ) ,
235
+ export default <%= componentName %>;
236
+ ` ,
237
+ ) ( { componentName, importsString, propsString, jsx } ) ) ,
225
238
reactElement : generateReactElement ( { name : componentName , props, jsx : selection } ) ,
226
239
imports,
227
240
name : componentName ,
@@ -242,4 +255,4 @@ module.exports = {
242
255
askForComponentName,
243
256
validateSelection,
244
257
updateOriginalComponent,
245
- } ;
258
+ } ;
0 commit comments