13 files changed

+486
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ var usage = 'Usage: flow-remove-types [options] [sources] \n' +
2828
' completely rather than only removing the type. THIS IS NOT\n' +
2929
' SPEC COMPLIANT! Instead, use `declare foo: string;` for\n' +
3030
' type-only fields.\n' +
31+
' --remove-empty-imports\n' +
32+
' If true, removes empty import statements that remain after removing\n' +
33+
' all type and typeof imports (e.g. `import {} from \'some-module\'`).\n' +
3134
' -m, --sourcemaps Also output source map files. Optionally pass "inline"\n' +
3235
' -q, --quiet Does not produce any output concerning successful progress.\n' +
3336

@@ -85,6 +88,7 @@ var outFile;
8588
var all;
8689
var pretty;
8790
var ignoreUninitializedFields;
91+
var removeEmptyImports;
8892
var sourceMaps;
8993
var inlineSourceMaps;
9094
var quiet;
@@ -112,6 +116,8 @@ while (i < process.argv.length) {
112116
pretty = true;
113117
} else if (arg === '--ignore-uninitialized-fields') {
114118
ignoreUninitializedFields = true;
119+
} else if (arg === '--remove-empty-imports') {
120+
removeEmptyImports = true;
115121
} else if (arg === '-m' || arg === '--sourcemaps') {
116122
sourceMaps = true;
117123
if (process.argv[i] === 'inline') {
@@ -254,6 +260,7 @@ function transformSource(content, filepath) {
254260
all: all,
255261
pretty: pretty,
256262
ignoreUninitializedFields: ignoreUninitializedFields,
263+
removeEmptyImports: removeEmptyImports,
257264
});
258265
} catch (error) {
259266
if (error.loc) {
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ var vlq = require('vlq');
2828
* completely rather than only removing the type. THIS IS NOT SPEC
2929
* COMPLIANT! Instead, use `declare foo: string;` for type-only fields.
3030
*
31+
* - removeEmptyImports: (default: false)
32+
* If true, removes empty import statements that remain after removing
33+
* all type and typeof imports (e.g. `import {} from 'some-module'`).
34+
*
3135
* Returns an object with two methods:
3236
*
3337
* - .toString()
@@ -69,6 +73,7 @@ module.exports = function flowRemoveTypes(source, options) {
6973
ignoreUninitializedFields: Boolean(
7074
options && options.ignoreUninitializedFields,
7175
),
76+
removeEmptyImports: Boolean(options && options.removeEmptyImports),
7277
};
7378

7479
// Remove the flow pragma.
@@ -239,6 +244,55 @@ var removeFlowVisitor = {
239244
if (node.importKind === 'type' || node.importKind === 'typeof') {
240245
return removeNode(context, node);
241246
}
247+
248+
if (
249+
context.removeEmptyImports &&
250+
node.importKind === 'value' &&
251+
node.specifiers.length > 0
252+
) {
253+
if (node.specifiers[0].type !== 'ImportDefaultSpecifier') {
254+
// Remove import declaration if all specifiers are type imports
255+
for (var i = 0; i < node.specifiers.length; i++) {
256+
if (
257+
node.specifiers[i].importKind !== 'type' &&
258+
node.specifiers[i].importKind !== 'typeof'
259+
) {
260+
return;
261+
}
262+
}
263+
return removeNode(context, node);
264+
} else if (node.specifiers.length > 1) {
265+
// Remove non-default specifiers completely
266+
// if all non-default specifiers are type imports
267+
for (var i = 1; i < node.specifiers.length; i++) {
268+
if (
269+
node.specifiers[i].importKind !== 'type' &&
270+
node.specifiers[i].importKind !== 'typeof'
271+
) {
272+
return;
273+
}
274+
}
275+
276+
var defaultSpecifier = node.specifiers[0];
277+
var firstSpecifier = node.specifiers[1];
278+
var lastSpecifier = node.specifiers[node.specifiers.length - 1];
279+
280+
var idxStart = findTokenIndexAtStartOfNode(
281+
context.ast.tokens,
282+
firstSpecifier,
283+
);
284+
var idxEnd = findTokenIndexAtEndOfNode(
285+
context.ast.tokens,
286+
lastSpecifier,
287+
);
288+
289+
removeTrailingCommaNode(context, defaultSpecifier);
290+
// remove opening brace
291+
removeNode(context, context.ast.tokens[idxStart - 1]);
292+
// remove closing brace
293+
removeNode(context, context.ast.tokens[idxEnd + 1]);
294+
}
295+
}
242296
},
243297

244298
ImportSpecifier: function (context, node) {
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
# Generate expected output with --ignore-uninitialized-fields flag
1111
./flow-remove-types --ignore-uninitialized-fields test/source.js > test/expected-uninitialized-fields.js;
1212

13+
# Generate expected output with --remove-empty-imports flag
14+
./flow-remove-types --remove-empty-imports test/source.js > test/expected-empty-imports.js;
15+
1316
# Generate expected output with --pretty flag
1417
./flow-remove-types --pretty test/source.js > test/expected-pretty.js;
1518

Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ echo "Test: flow-remove-types --ignore-uninitialized-fields test/source.js"
1414
DIFF=$(./flow-remove-types --ignore-uninitialized-fields test/source.js | diff test/expected-uninitialized-fields.js -);
1515
if [ -n "$DIFF" ]; then echo "$DIFF"; exit 1; fi;
1616

17+
# Test expected output with --remove-empty-imports flag
18+
echo "Test: flow-remove-types --remove-empty-imports test/source.js"
19+
DIFF=$(./flow-remove-types --remove-empty-imports test/source.js | diff test/expected-empty-imports.js -);
20+
if [ -n "$DIFF" ]; then echo "$DIFF"; exit 1; fi;
21+
1722
# Test expected output with --pretty flag
1823
echo "Test: flow-remove-types --pretty test/source.js"
1924
DIFF=$(./flow-remove-types --pretty test/source.js | diff test/expected-pretty.js -);

0 commit comments

Comments
 (0)