flow-remove-types 1.1.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -7
- package/flow-remove-types +17 -7
- package/index.js +163 -17
- package/package.json +5 -5
- package/register.js +34 -6
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@ flow-remove-types
|
|
|
2
2
|
=================
|
|
3
3
|
|
|
4
4
|
[](https://www.npmjs.com/package/flow-remove-types)
|
|
5
|
-
[](https://travis-ci.org/flowtype/flow-remove-types)
|
|
6
6
|
|
|
7
7
|
Turn your JavaScript with [Flow](https://flowtype.org/) type annotations into
|
|
8
8
|
standard JavaScript in an instant with no configuration and minimal setup.
|
|
@@ -89,10 +89,6 @@ require('flow-remove-types/register')
|
|
|
89
89
|
require('./some-module-with-flow-type-syntax')
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
As always, don't forget to use `flow-remove-types` to compile files before
|
|
93
|
-
distributing your code on npm, as using the require hook affects the whole
|
|
94
|
-
runtime and not just your module.
|
|
95
|
-
|
|
96
92
|
You can also provide options to the require hook:
|
|
97
93
|
|
|
98
94
|
```js
|
|
@@ -100,14 +96,19 @@ You can also provide options to the require hook:
|
|
|
100
96
|
require('flow-remove-types/register')({ all: true })
|
|
101
97
|
```
|
|
102
98
|
|
|
103
|
-
Use options to define exactly which files to `
|
|
99
|
+
Use options to define exactly which files to `includes` or `excludes` with regular
|
|
104
100
|
expressions. All files are included by default except those found in the
|
|
105
101
|
`node_modules` folder, which is excluded by default.
|
|
106
102
|
|
|
107
103
|
```js
|
|
108
|
-
require('flow-remove-types/register')({
|
|
104
|
+
require('flow-remove-types/register')({ includes: /\/custom_path\// })
|
|
109
105
|
```
|
|
110
106
|
|
|
107
|
+
> #### Don't use the require hook in packages distributed on NPM
|
|
108
|
+
> As always, don't forget to use `flow-remove-types` to compile files before distributing
|
|
109
|
+
> your code on npm, as using the require hook affects the whole runtime and not
|
|
110
|
+
> just your module and may hurt the runtime performance of code that includes it.
|
|
111
|
+
|
|
111
112
|
|
|
112
113
|
## Dead-Simple Transforms
|
|
113
114
|
|
package/flow-remove-types
CHANGED
|
@@ -18,6 +18,7 @@ var usage = 'Usage: flow-remove-types [options] [sources] \n' +
|
|
|
18
18
|
' -p, --pretty Remove flow types without replacing with spaces, \n' +
|
|
19
19
|
' producing prettier output but may require using source maps\n' +
|
|
20
20
|
' -m, --sourcemaps Also output source map files. Optionally pass "inline"\n' +
|
|
21
|
+
' -q, --quiet Does not produce any output concerning successful progress.\n' +
|
|
21
22
|
|
|
22
23
|
'\nExamples:\n' +
|
|
23
24
|
|
|
@@ -39,11 +40,6 @@ var usage = 'Usage: flow-remove-types [options] [sources] \n' +
|
|
|
39
40
|
'\nTransform stdin:\n' +
|
|
40
41
|
' cat input.js | flow-remove-types > output.js\n';
|
|
41
42
|
|
|
42
|
-
function error(msg) {
|
|
43
|
-
process.stderr.write('\n\033[31m ' + msg + '\033[0m\n\n');
|
|
44
|
-
process.exit(1);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
43
|
var _memo = {};
|
|
48
44
|
|
|
49
45
|
function mkdirp(dirpath) {
|
|
@@ -79,6 +75,7 @@ var all;
|
|
|
79
75
|
var pretty;
|
|
80
76
|
var sourceMaps;
|
|
81
77
|
var inlineSourceMaps;
|
|
78
|
+
var quiet;
|
|
82
79
|
var sources = [];
|
|
83
80
|
var i = 2;
|
|
84
81
|
while (i < process.argv.length) {
|
|
@@ -107,11 +104,24 @@ while (i < process.argv.length) {
|
|
|
107
104
|
inlineSourceMaps = true;
|
|
108
105
|
i++;
|
|
109
106
|
}
|
|
107
|
+
} else if (arg === '-q' || arg === '--quiet') {
|
|
108
|
+
quiet = true;
|
|
110
109
|
} else {
|
|
111
110
|
sources.push(arg);
|
|
112
111
|
}
|
|
113
112
|
}
|
|
114
113
|
|
|
114
|
+
function info(msg) {
|
|
115
|
+
if (!quiet) {
|
|
116
|
+
process.stderr.write(msg);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function error(msg) {
|
|
121
|
+
process.stderr.write('\n\033[31m ' + msg + '\033[0m\n\n');
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
|
|
115
125
|
// Validate arguments
|
|
116
126
|
if (outDir && outFile) {
|
|
117
127
|
error('Only specify one of --out-dir or --out-file');
|
|
@@ -204,11 +214,11 @@ function transformAndOutput(content, outFile, source) {
|
|
|
204
214
|
|
|
205
215
|
if (outFile) {
|
|
206
216
|
fs.writeFileSync(outFile, code);
|
|
207
|
-
|
|
217
|
+
info(fileName + '\n \u21B3 \033[32m' + outFile + '\033[0m\n');
|
|
208
218
|
if (sourceMaps && !inlineSourceMaps) {
|
|
209
219
|
var mapOutFile = outFile + '.map';
|
|
210
220
|
fs.writeFileSync(mapOutFile, JSON.stringify(map) + '\n');
|
|
211
|
-
|
|
221
|
+
info('\033[2m \u21B3 \033[32m' + mapOutFile + '\033[0m\n');
|
|
212
222
|
}
|
|
213
223
|
} else {
|
|
214
224
|
process.stdout.write(code);
|
package/index.js
CHANGED
|
@@ -69,7 +69,14 @@ module.exports = function flowRemoveTypes(source, options) {
|
|
|
69
69
|
plugins: [ '*', 'jsx', 'flow' ],
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
var context = {
|
|
73
|
+
ast: ast,
|
|
74
|
+
source: source,
|
|
75
|
+
removedNodes: removedNodes,
|
|
76
|
+
pretty: Boolean(options && options.pretty)
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
visit(ast, context, removeFlowVisitor);
|
|
73
80
|
|
|
74
81
|
return resultPrinter(options, source, removedNodes);
|
|
75
82
|
}
|
|
@@ -139,39 +146,56 @@ var removeFlowVisitor = {
|
|
|
139
146
|
ClassDeclaration: removeImplementedInterfaces,
|
|
140
147
|
ClassExpression: removeImplementedInterfaces,
|
|
141
148
|
|
|
142
|
-
Identifier: function (
|
|
149
|
+
Identifier: function (context, node, ast) {
|
|
143
150
|
if (node.optional) {
|
|
144
151
|
// Find the optional token.
|
|
145
152
|
var idx = findTokenIndex(ast.tokens, node.start);
|
|
146
153
|
do {
|
|
147
154
|
idx++;
|
|
148
155
|
} while (ast.tokens[idx].type.label !== '?');
|
|
149
|
-
removeNode(
|
|
156
|
+
removeNode(context, ast.tokens[idx]);
|
|
150
157
|
}
|
|
151
158
|
},
|
|
152
159
|
|
|
153
|
-
ClassProperty: function (
|
|
160
|
+
ClassProperty: function (context, node) {
|
|
154
161
|
if (!node.value) {
|
|
155
|
-
return removeNode(
|
|
162
|
+
return removeNode(context, node)
|
|
156
163
|
}
|
|
157
164
|
},
|
|
158
165
|
|
|
159
|
-
ExportNamedDeclaration: function (
|
|
160
|
-
if (node.exportKind === 'type') {
|
|
161
|
-
return removeNode(
|
|
166
|
+
ExportNamedDeclaration: function (context, node) {
|
|
167
|
+
if (node.exportKind === 'type' || node.exportKind === 'typeof') {
|
|
168
|
+
return removeNode(context, node);
|
|
162
169
|
}
|
|
163
170
|
},
|
|
164
171
|
|
|
165
|
-
ImportDeclaration: function (
|
|
166
|
-
if (node.importKind === 'type') {
|
|
167
|
-
return removeNode(
|
|
172
|
+
ImportDeclaration: function (context, node) {
|
|
173
|
+
if (node.importKind === 'type' || node.importKind === 'typeof') {
|
|
174
|
+
return removeNode(context, node);
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
ImportSpecifier: function(context, node) {
|
|
179
|
+
if (node.importKind === 'type' || node.importKind === 'typeof') {
|
|
180
|
+
removeNode(context, node);
|
|
181
|
+
|
|
182
|
+
// Remove trailing comma
|
|
183
|
+
var ast = context.ast;
|
|
184
|
+
var idx = findTokenIndex(ast.tokens, node.end);
|
|
185
|
+
while (isComment(ast.tokens[idx])) {
|
|
186
|
+
idx++;
|
|
187
|
+
}
|
|
188
|
+
if (ast.tokens[idx].type.label === ',') {
|
|
189
|
+
removeNode(context, ast.tokens[idx]);
|
|
190
|
+
}
|
|
191
|
+
return false;
|
|
168
192
|
}
|
|
169
193
|
}
|
|
170
194
|
};
|
|
171
195
|
|
|
172
196
|
// If this class declaration or expression implements interfaces, remove
|
|
173
197
|
// the associated tokens.
|
|
174
|
-
function removeImplementedInterfaces(
|
|
198
|
+
function removeImplementedInterfaces(context, node, ast) {
|
|
175
199
|
if (node.implements && node.implements.length > 0) {
|
|
176
200
|
var first = node.implements[0];
|
|
177
201
|
var last = node.implements[node.implements.length - 1];
|
|
@@ -182,9 +206,8 @@ function removeImplementedInterfaces(removedNodes, node, ast) {
|
|
|
182
206
|
|
|
183
207
|
var lastIdx = findTokenIndex(ast.tokens, last.start);
|
|
184
208
|
do {
|
|
185
|
-
if (ast.tokens[idx]
|
|
186
|
-
|
|
187
|
-
removeNode(removedNodes, ast.tokens[idx]);
|
|
209
|
+
if (!isComment(ast.tokens[idx])) {
|
|
210
|
+
removeNode(context, ast.tokens[idx]);
|
|
188
211
|
}
|
|
189
212
|
} while (idx++ !== lastIdx);
|
|
190
213
|
}
|
|
@@ -192,17 +215,131 @@ function removeImplementedInterfaces(removedNodes, node, ast) {
|
|
|
192
215
|
|
|
193
216
|
// Append node to the list of removed nodes, ensuring the order of the nodes
|
|
194
217
|
// in the list.
|
|
195
|
-
function removeNode(
|
|
218
|
+
function removeNode(context, node) {
|
|
219
|
+
var removedNodes = context.removedNodes;
|
|
196
220
|
var length = removedNodes.length;
|
|
197
221
|
var index = length;
|
|
222
|
+
|
|
223
|
+
// Check for line's leading and trailing space to be removed.
|
|
224
|
+
var spaceNode = context.pretty ? getLeadingSpaceNode(context, node) : null;
|
|
225
|
+
var lineNode = context.pretty ? getTrailingLineNode(context, node) : null;
|
|
226
|
+
|
|
198
227
|
while (index > 0 && removedNodes[index - 1].end > node.start) {
|
|
199
228
|
index--;
|
|
200
229
|
}
|
|
230
|
+
|
|
201
231
|
if (index === length) {
|
|
232
|
+
if (spaceNode) {
|
|
233
|
+
removedNodes.push(spaceNode);
|
|
234
|
+
}
|
|
202
235
|
removedNodes.push(node);
|
|
236
|
+
if (lineNode) {
|
|
237
|
+
removedNodes.push(lineNode);
|
|
238
|
+
}
|
|
203
239
|
} else {
|
|
204
|
-
|
|
240
|
+
if (lineNode) {
|
|
241
|
+
if (spaceNode) {
|
|
242
|
+
removedNodes.splice(index, 0, spaceNode, node, lineNode);
|
|
243
|
+
} else {
|
|
244
|
+
removedNodes.splice(index, 0, node, lineNode);
|
|
245
|
+
}
|
|
246
|
+
} else if (spaceNode) {
|
|
247
|
+
removedNodes.splice(index, 0, spaceNode, node);
|
|
248
|
+
} else {
|
|
249
|
+
removedNodes.splice(index, 0, node);
|
|
250
|
+
}
|
|
205
251
|
}
|
|
252
|
+
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function getLeadingSpaceNode(context, node) {
|
|
257
|
+
var source = context.source;
|
|
258
|
+
var end = node.start;
|
|
259
|
+
var start = end;
|
|
260
|
+
while (source[start - 1] === ' ' || source[start - 1] === '\t') {
|
|
261
|
+
start--;
|
|
262
|
+
}
|
|
263
|
+
if (start !== end) {
|
|
264
|
+
return {
|
|
265
|
+
start: start,
|
|
266
|
+
end: end,
|
|
267
|
+
loc: { start: node.loc.start, end: node.loc.start }
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function getTrailingLineNode(context, node) {
|
|
273
|
+
var source = context.source;
|
|
274
|
+
var start = node.end;
|
|
275
|
+
var end = start;
|
|
276
|
+
while (source[end] === ' ' || source[end] === '\t') {
|
|
277
|
+
end++;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Remove all space including the line break if this token was alone on the line.
|
|
281
|
+
if (source[end] === '\n' || source[end] === '\r') {
|
|
282
|
+
if (source[end] === '\r' && source[end + 1] === '\n') {
|
|
283
|
+
end++;
|
|
284
|
+
}
|
|
285
|
+
end++;
|
|
286
|
+
|
|
287
|
+
if (isLastNodeRemovedFromLine(context, node)) {
|
|
288
|
+
return {
|
|
289
|
+
start: start,
|
|
290
|
+
end: end,
|
|
291
|
+
loc: { start: node.loc.end, end: node.loc.end }
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Returns true if node is the last to be removed from a line.
|
|
298
|
+
function isLastNodeRemovedFromLine(context, node) {
|
|
299
|
+
var tokens = context.ast.tokens;
|
|
300
|
+
var priorTokenIdx = findTokenIndex(tokens, node.start) - 1;
|
|
301
|
+
var token = tokens[priorTokenIdx];
|
|
302
|
+
var line = node.loc.end.line;
|
|
303
|
+
|
|
304
|
+
// Find previous token that was not removed on the same line.
|
|
305
|
+
while (priorTokenIdx >= 0 &&
|
|
306
|
+
token.loc.end.line === line &&
|
|
307
|
+
isRemovedToken(context, token)) {
|
|
308
|
+
token = tokens[--priorTokenIdx]
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// If there's no prior token (start of file), or the prior token is on another
|
|
312
|
+
// line, this line must be fully removed.
|
|
313
|
+
return !token || token.loc.end.line !== line;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Returns true if the provided token was previously marked as removed.
|
|
317
|
+
function isRemovedToken(context, token) {
|
|
318
|
+
var removedNodes = context.removedNodes;
|
|
319
|
+
var nodeIdx = removedNodes.length - 1;
|
|
320
|
+
|
|
321
|
+
// Find the last removed node which could possibly contain this token.
|
|
322
|
+
while (nodeIdx >= 0 && removedNodes[nodeIdx].start > token.start) {
|
|
323
|
+
nodeIdx--;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
var node = removedNodes[nodeIdx];
|
|
327
|
+
|
|
328
|
+
// This token couldn't be removed if not contained within the removed node.
|
|
329
|
+
if (nodeIdx === -1 || node.end < token.end) {
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Iterate through the tokens contained by the removed node to find a match.
|
|
334
|
+
var tokens = context.ast.tokens;
|
|
335
|
+
var tokenIdx = findTokenIndex(tokens, node.start);
|
|
336
|
+
while (tokens[tokenIdx].end <= node.end) {
|
|
337
|
+
if (token === tokens[tokenIdx]) {
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
tokenIdx++;
|
|
341
|
+
}
|
|
342
|
+
|
|
206
343
|
return false;
|
|
207
344
|
}
|
|
208
345
|
|
|
@@ -260,6 +397,11 @@ function findTokenIndex(tokens, offset) {
|
|
|
260
397
|
return ptr;
|
|
261
398
|
}
|
|
262
399
|
|
|
400
|
+
// True if the provided token is a comment.
|
|
401
|
+
function isComment(token) {
|
|
402
|
+
return token.type === 'CommentBlock' || token.type === 'CommentLine';
|
|
403
|
+
}
|
|
404
|
+
|
|
263
405
|
// Produce a string full of space characters of a given size.
|
|
264
406
|
function space(size) {
|
|
265
407
|
var sp = ' '
|
|
@@ -282,6 +424,10 @@ function space(size) {
|
|
|
282
424
|
// with spaces.
|
|
283
425
|
function generateSourceMappings(removedNodes) {
|
|
284
426
|
var mappings = '';
|
|
427
|
+
if (!removedNodes || removedNodes.length === '') {
|
|
428
|
+
return mappings;
|
|
429
|
+
}
|
|
430
|
+
|
|
285
431
|
var end = { line: 1, column: 0 };
|
|
286
432
|
|
|
287
433
|
for (var i = 0; i < removedNodes.length; i++) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flow-remove-types",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Removes Flow type annotations from JavaScript files with speed and simplicity.",
|
|
5
5
|
"author": "Lee Byron <lee@leebyron.com> (http://leebyron.com/)",
|
|
6
6
|
"license": "BSD-3-Clause",
|
|
@@ -17,13 +17,13 @@
|
|
|
17
17
|
"LICENSE",
|
|
18
18
|
"PATENTS"
|
|
19
19
|
],
|
|
20
|
-
"homepage": "https://github.com/
|
|
20
|
+
"homepage": "https://github.com/flowtype/flow-remove-types",
|
|
21
21
|
"bugs": {
|
|
22
|
-
"url": "https://github.com/
|
|
22
|
+
"url": "https://github.com/flowtype/flow-remove-types/issues"
|
|
23
23
|
},
|
|
24
24
|
"repository": {
|
|
25
25
|
"type": "git",
|
|
26
|
-
"url": "http://github.com/
|
|
26
|
+
"url": "http://github.com/flowtype/flow-remove-types.git"
|
|
27
27
|
},
|
|
28
28
|
"scripts": {
|
|
29
29
|
"test": "./test.sh",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"es6"
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"babylon": "^6.
|
|
41
|
+
"babylon": "^6.15.0",
|
|
42
42
|
"vlq": "^0.2.1"
|
|
43
43
|
}
|
|
44
44
|
}
|
package/register.js
CHANGED
|
@@ -3,9 +3,11 @@ var flowRemoveTypes = require('./index');
|
|
|
3
3
|
// Supported options:
|
|
4
4
|
//
|
|
5
5
|
// - all: Transform all files, not just those with a @flow comment.
|
|
6
|
-
// - includes: A Regexp to determine which files should be transformed.
|
|
7
|
-
//
|
|
8
|
-
//
|
|
6
|
+
// - includes: A Regexp/String to determine which files should be transformed.
|
|
7
|
+
// (alias: include)
|
|
8
|
+
// - excludes: A Regexp/String to determine which files should not be
|
|
9
|
+
// transformed, defaults to ignoring /node_modules/, provide null
|
|
10
|
+
// to exclude nothing. (alias: exclude)
|
|
9
11
|
var options;
|
|
10
12
|
module.exports = function setOptions(newOptions) {
|
|
11
13
|
options = newOptions;
|
|
@@ -32,7 +34,33 @@ exts.forEach(function (ext) {
|
|
|
32
34
|
});
|
|
33
35
|
|
|
34
36
|
function shouldTransform(filename, options) {
|
|
35
|
-
var includes = options && options.includes;
|
|
36
|
-
var excludes =
|
|
37
|
-
|
|
37
|
+
var includes = options && regexpPattern(options.includes || options.include);
|
|
38
|
+
var excludes =
|
|
39
|
+
options && 'excludes' in options ? regexpPattern(options.excludes) :
|
|
40
|
+
options && 'exclude' in options ? regexpPattern(options.exclude) :
|
|
41
|
+
/\/node_modules\//;
|
|
42
|
+
return (!includes || includes.test(filename)) && !(excludes && excludes.test(filename));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Given a null | string | RegExp | any, returns null | Regexp or throws a
|
|
46
|
+
// more helpful error.
|
|
47
|
+
function regexpPattern(pattern) {
|
|
48
|
+
if (!pattern) {
|
|
49
|
+
return pattern;
|
|
50
|
+
}
|
|
51
|
+
// A very simplified glob transform which allows passing legible strings like
|
|
52
|
+
// "myPath/*.js" instead of a harder to read RegExp like /\/myPath\/.*\.js/.
|
|
53
|
+
if (typeof pattern === 'string') {
|
|
54
|
+
pattern = pattern.replace(/\./g, '\\.').replace(/\*/g, '.*');
|
|
55
|
+
if (pattern[0] !== '/') {
|
|
56
|
+
pattern = '/' + pattern;
|
|
57
|
+
}
|
|
58
|
+
return new RegExp(pattern);
|
|
59
|
+
}
|
|
60
|
+
if (typeof pattern.test === 'function') {
|
|
61
|
+
return pattern;
|
|
62
|
+
}
|
|
63
|
+
throw new Error(
|
|
64
|
+
'flow-remove-types: includes and excludes must be RegExp or path strings. Got: ' + pattern
|
|
65
|
+
);
|
|
38
66
|
}
|