Skip to content

Commit 7cee86b

Browse files
author
Sahar Avr
committed
[FEAT] new component build - use template for component code
[REFACTOR] clean code - implement popular eslint rules [CLEANUP] junk files - remove .DS_Store traces
1 parent 31a8fb8 commit 7cee86b

File tree

4 files changed

+96
-84
lines changed

4 files changed

+96
-84
lines changed

src/.DS_Store

-6 KB
Binary file not shown.

src/extension.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const {
1010
const activate = context => {
1111
context.subscriptions.push(vscode.commands.registerCommand(
1212
'react-component-splitter.split',
13-
async () => {
13+
async () => {
1414
try {
1515

1616
validateSelection();

src/utils/parse.js

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ const linter = new (
6565

6666
}
6767
}
68-
);
68+
)();
6969

7070
const transformCode = code => transformSync(code, {
7171
presets: [babelPresetReact],
@@ -102,7 +102,16 @@ const getUndefinedVars = code => {
102102

103103
};
104104

105-
const getUsedImports = (code, options = { transform: true }) => {
105+
const getImports = (code, options = { transform: true }) => {
106+
107+
return _.chain(options?.transform ? transformCode(code) : code)
108+
.split('\n')
109+
.filter(codeLine => /^\s*import.*from.*/.test(codeLine))
110+
.value();
111+
112+
};
113+
114+
const getUsedImports = (code, options = { transform: true }) => {
106115

107116
const {output} = linter.verifyAndFix(
108117
options?.transform ? transformCode(code) : code, {
@@ -126,15 +135,6 @@ const pretify = code => {
126135

127136
};
128137

129-
const getImports = (code, options = { transform: true }) => {
130-
131-
return _.chain(options?.transform ? transformCode(code) : code)
132-
.split('\n')
133-
.filter(codeLine => /^\s*import.*from.*/.test(codeLine))
134-
.value();
135-
136-
};
137-
138138
const getNumberOfLeadingSpaces = (code, options = { endToStart: false }) => {
139139

140140
const codeLines = _.split(code, '\n');
@@ -144,7 +144,7 @@ const getNumberOfLeadingSpaces = (code, options = { endToStart: false }) => {
144144
}
145145

146146
const firstCodeLineIndex = _.findIndex(codeLines, line =>
147-
options?.endToStart ? /^\s*[<|\/>].*$/.test(line) : /^\s*<.*$/.test(line));
147+
(options?.endToStart ? /^\s*[<|\/>].*$/.test(line) : /^\s*<.*$/.test(line)));
148148
const firstSpaceIndex = codeLines[firstCodeLineIndex].search(/\S/);
149149

150150
return Math.max(0, firstSpaceIndex);
@@ -173,7 +173,6 @@ const eslintAutofix = (code, { filePath }) => {
173173

174174
};
175175

176-
177176
module.exports = {
178177
eslintAutofix,
179178
getImports,
@@ -183,4 +182,4 @@ module.exports = {
183182
getUsedImports,
184183
pretify,
185184
transformCode,
186-
};
185+
};

src/utils/splitter.js

Lines changed: 82 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,62 @@ const fs = require('fs');
44
const path = require('path');
55
const 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+
737
const 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

2258
const 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-
7985
const 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

94100
const 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-
147152
const 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-
190177
const buildImportsString = imports => _.join(imports, '\n');
191178

192179
const 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+
204209
const 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

209217
const 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

Comments
 (0)