@@ -4,26 +4,62 @@ const fs = require('fs');
44const path = require ( 'path' ) ;
55const parseUtils = require ( './parse' ) ;
66
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+
737const validateSelection = ( ) => {
838
939 const editor = vscode . window . activeTextEditor ;
1040 const selection = editor . document . getText ( editor . selection ) ;
1141
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+ }
1447
1548 const codeWithoutSelection = replaceCodeByRange ( editor . document . getText ( ) , editor . selection , '<></>' ) ;
1649
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+ }
1955
2056} ;
2157
2258const buildComponentPath = name => {
2359
2460 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 ( / \. [ ^ \\ . ] + $ / , '' ) ;
2763
2864 return path . join ( activeDocumentPath , '..' , `${ nameWithoutExtension } .${ activeDocumentExtension } ` ) ;
2965
@@ -46,36 +82,6 @@ const askForComponentName = async () => {
4682 return name ;
4783} ;
4884
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-
7985const getFullDocumentRange = document => new vscode . Range (
8086 document . positionAt ( 0 ) ,
8187 document . positionAt ( _ . size ( document . getText ( ) ) ) ,
@@ -89,7 +95,7 @@ const getFirstAndLastImportLineIndexes = codeLines => {
8995
9096 return { firstImportLineIndex, lastImportLineIndex} ;
9197
92- }
98+ } ;
9399
94100const replaceSelection = async ( { reactElement, name } ) => {
95101
@@ -101,7 +107,7 @@ const replaceSelection = async ({ reactElement, name }) => {
101107 await editor . edit ( edit => {
102108 edit . replace ( editor . selection , reactElement ) ;
103109 edit . insert ( new vscode . Position ( ( lastImportLineIndex + 1 ) , 0 ) , `import ${ name } from './${ name } ';\n` ) ;
104- } ) ;
110+ } ) ;
105111
106112 parseUtils . eslintAutofix ( document . getText ( ) , { filePath : document . uri . fsPath } )
107113 . then ( output => {
@@ -128,7 +134,7 @@ const removeUnusedImports = async () => {
128134 const usedImportsString = _ . join ( parseUtils . getUsedImports ( code ) , '\n' ) ;
129135 const codeWithUsedImports = _ . replace ( code , importsString , usedImportsString ) ;
130136
131- await editor . edit ( edit => edit . replace ( getFullDocumentRange ( document ) , codeWithUsedImports ) ) ;
137+ await editor . edit ( edit => edit . replace ( getFullDocumentRange ( document ) , codeWithUsedImports ) ) ;
132138
133139 parseUtils . eslintAutofix ( document . getText ( ) , { filePath : document . uri . fsPath } )
134140 . then ( output => {
@@ -143,7 +149,6 @@ const removeUnusedImports = async () => {
143149
144150} ;
145151
146-
147152const updateOriginalComponent = async ( { newComponent } ) => {
148153
149154 await replaceSelection ( newComponent ) ;
@@ -169,59 +174,67 @@ const generateReactElement = ({ name, props, jsx }) => {
169174 return `${ leadingSpacesFromStart } <${ name } ${ propsString } />` ;
170175} ;
171176
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-
190177const buildImportsString = imports => _ . join ( imports , '\n' ) ;
191178
192179const buildPropsString = props => {
193180
194181 const numberOfProps = _ . size ( props ) ;
195182
196- if ( numberOfProps > 2 ) { return `{\n ${ _ . join ( props , ` ,\n ` ) } ,\n}` ; }
183+ if ( numberOfProps > 2 ) { return `{\n ${ _ . join ( props , ' ,\n ' ) } ,\n}` ; }
197184 if ( numberOfProps === 2 ) { return `{${ _ . join ( props , ', ' ) } }` ; }
198185 if ( numberOfProps === 1 ) { return `{${ props [ 0 ] } }` ; }
199186
200187 return '' ;
201188
202189} ;
203190
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+
204209const shouldWrapCodeWithEmptyTag = code => {
205- try { parseUtils . transformCode ( code ) ; }
206- catch { return true ; }
210+ try {
211+ parseUtils . transformCode ( code ) ;
212+ } catch {
213+ return true ;
214+ }
207215} ;
208216
209217const createNewComponent = async componentName => {
210218
211219 const editor = vscode . window . activeTextEditor ;
212220 const selection = editor . document . getText ( editor . selection ) ;
213221 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 ) ;
214226
215227 const newComponent = {
216- code : parseUtils . pretify (
217- ` ${ buildImportsString ( imports ) } \n\n` +
228+ code : parseUtils . pretify ( _ . template (
229+ `<%= importsString %>
218230
219- ` const ${ componentName } = (${ buildPropsString ( props ) } ) => (\n` +
220- ` ${ shouldWrapCodeWithEmptyTag ( selection ) ? `<>\n ${ selection } \n</>` : selection } \n` +
221- `);\n\n` +
231+ const <%= componentName %> = (<%= propsString %>) => (
232+ <%= jsx %>
233+ );
222234
223- `export default ${ componentName } ;\n` ,
224- ) ,
235+ export default <%= componentName %>;
236+ ` ,
237+ ) ( { componentName, importsString, propsString, jsx } ) ) ,
225238 reactElement : generateReactElement ( { name : componentName , props, jsx : selection } ) ,
226239 imports,
227240 name : componentName ,
@@ -242,4 +255,4 @@ module.exports = {
242255 askForComponentName,
243256 validateSelection,
244257 updateOriginalComponent,
245- } ;
258+ } ;
0 commit comments