UNPKG

11.3 kBMarkdownView Raw
1# JSTransform [![Build Status](https://travis-ci.org/facebook/jstransform.svg?branch=master)](https://travis-ci.org/facebook/jstransform)
2
3A simple utility for pluggable JS syntax transforms using the esprima parser.
4
5* Makes it simple to write and plug-in syntax transformations
6* Makes it simple to coalesce multiple syntax transformations in a single pass of the AST
7* Gives complete control over the formatting of the output on a per-transformation basis
8* Supports source map generation
9* Comes pre-bundled with a small set of (optional) ES6 -> ES5 transforms
10
11- - -
12
13**Note:**
14If you're looking for a library for writing new greenfield JS transformations, consider looking at [Babel](https://github.com/babel/babel) or [Recast](https://github.com/benjamn/recast) instead of jstransform. We are still supporting jstransform (and intend to for a little while), but longer term we would like to direct efforts toward other open source projects that do a far better job of supporting a multi-pass JS transformation pipeline. This is important when attempting to apply many transformations to a source file. jstransform does a single pass resulting in performance benefits, but the tradeoff is that many transformations are much harder to write.
15
16- - -
17
18## Usage
19
20### Advanced API
21
22```js
23var jstranform = require('jstransform')
24```
25
26This is the API that jstransform has always supported. It gives very fine control over the transforms you use and what order they are run in. It also allows the use of custom transforms.
27
28#### `jstransform.transform(visitors, code, options={})`
29
30**`visitors`**
31Array of visitors. See [the React JSX visitors](https://github.com/facebook/jstransform/blob/master/visitors/react-jsx-visitors.js) as an example of what a visitor looks like.
32
33**`code`**
34String of code to be transformed.
35
36**`options`**
37Object with options that will be passed through to esprima and transforms.
38
39#### `jstransform.Syntax`
40
41This is the `Syntax` object re-exported from `esprima`. This is available because visitors will need access to this in order to effectively write transforms. By re-exporting we avoid the problem of conflicting versions of esprima being used.
42
43
44### Simple API
45
46```js
47var simple = require('jstransform/simple')
48```
49
50The simple API was added to mirror the new command line interface. It works similarly to how `react-tools` worked - there is no need to know exactly which transforms to run. Instead transforms are selected automatically based on the options.
51
52#### `simple.transform(code, options={})`
53
54**`code`**
55String of code to be transformed.
56
57**`options`**
58Object with options. Available options are:
59
60option | values | default
61-------|--------|--------
62`react` | `true`: enable React transforms (JSX, displayName) | `false`
63`es6` | `true`: enable ES6 transforms | `false`
64`es7` | `true`: enable ES7 transforms | `false`
65`harmony` | `true`: shortcut to enable ES6 & ES7 transforms | `false`
66`utility` | `true`: enable utility transforms (trailing commas in objects, arrays) | `false`
67`target` | `es3`: generate ES3 compatible code<br>`es5`: generate ES5 compatible code | `es5`
68`stripTypes` | `true`: strips out Flow type annotations | `false`
69`sourceMap` | `true`: generate and return a Source Map | `false`
70`sourceMapInline` | `true`: append inline source map at the end of the transformed source | `false`
71`sourceFilename` | the output filename for the source map | `"source.js"`
72`es6module` | `true`: parses the file as an ES6 module | `false`
73`nonStrictEs6module` | `true`: parses the file as an ES6 module, except disables implicit strict-mode (i.e. CommonJS modules et al are allowed) | `false`
74
75*Returns:* An Object with the following:
76
77**`code`**: the transformed code
78
79**`sourceMap`**: the source map object or `null`
80
81#### `simple.transformFile(file, options={}, callback)`
82
83**`file`**
84String of path to a file to transform. Will be passed directly to `fs.readFile`.
85
86**`options`**
87See `transform` API.
88
89**`callback`**
90Function to call with the result, where `result` is return value of `transform`.
91
92```js
93callback(err, result)
94```
95
96#### `simple.transformFileSync(file, options={})`
97
98The same as `transformFile` but the file is read synchronously.
99
100
101### CLI
102
103JSTransform now ships with a CLI. It was taken from the `react-tools` CLI so should be very familiar.
104
105```sh
106% jstransform --help
107
108 Usage: jstransform [options] <source directory> <output directory> [<module ID> [<module ID> ...]]
109
110 Options:
111
112 -h, --help output usage information
113 -V, --version output the version number
114 -c, --config [file] JSON configuration file (no file or - means STDIN)
115 -w, --watch Continually rebuild
116 -x, --extension <js | coffee | ...> File extension to assume when resolving module identifiers
117 --relativize Rewrite all module identifiers to be relative
118 --follow-requires Scan modules for required dependencies
119 --use-provides-module Respect @providesModules pragma in files
120 --cache-dir <directory> Alternate directory to use for disk cache
121 --no-cache-dir Disable the disk cache
122 --source-charset <utf8 | win1252 | ...> Charset of source (default: utf8)
123 --output-charset <utf8 | win1252 | ...> Charset of output (default: utf8)
124 --react Turns on the React JSX and React displayName transforms
125 --es6 Turns on available ES6 transforms
126 --es7 Turns on available ES7 transforms
127 --harmony Shorthand to enable all ES6 and ES7 transforms
128 --utility Turns on available utility transforms
129 --target [version] Specify your target version of ECMAScript. Valid values are "es3" and "es5". The default is "es5". "es3" will avoid uses of defineProperty and will quote reserved words. WARNING: "es5" is not properly supported, even with the use of es5shim, es5sham. If you need to support IE8, use "es3".
130 --strip-types Strips out type annotations.
131 --es6module Parses the file as a valid ES6 module. (Note that this means implicit strict mode)
132 --non-strict-es6module Parses the file as an ES6 module, except disables implicit strict-mode. (This is useful if you're porting non-ES6 modules to ES6, but haven't yet verified that they are strict-mode safe yet)
133 --source-map-inline Embed inline sourcemap in transformed source
134 --source-filename Filename to use when generating the inline sourcemap. Will default to filename when processing files
135```
136
137## Examples
138
139### Advanced API
140
141#### Using a pre-bundled or existing transform:
142
143```js
144/**
145 * Reads a source file that may (or may not) contain ES6 classes, transforms it
146 * to ES5 compatible code using the pre-bundled ES6 class visitors, and prints
147 * out the result.
148 */
149var es6ClassVisitors = require('jstransform/visitors/es6-class-visitors').visitorList;
150var fs = require('fs');
151var jstransform = require('jstransform');
152
153var originalFileContents = fs.readFileSync('path/to/original/file.js', 'utf-8');
154
155var transformedFileData = jstransform.transform(
156 es6ClassVisitors,
157 originalFileContents
158);
159
160console.log(transformedFileData.code);
161```
162
163#### Using multiple pre-bundled or existing transforms at once:
164
165```js
166/**
167 * Reads a source file that may (or may not) contain ES6 classes *or* arrow
168 * functions, transforms them to ES5 compatible code using the pre-bundled ES6
169 * visitors, and prints out the result.
170 */
171var es6ArrowFuncVisitors = require('jstransform/visitors/es6-arrow-function-visitors').visitorList;
172var es6ClassVisitors = require('jstransform/visitors/es6-class-visitors').visitorList;
173var jstransform = require('jstransform');
174
175// Normally you'd read this from the filesystem, but I'll just use a string here
176// to simplify the example.
177var originalFileContents = "var a = (param1) => param1; class FooClass {}";
178
179var transformedFileData = jstransform.transform(
180 es6ClassVisitors.concat(es6ArrowFuncVisitors),
181 originalFileContents
182);
183
184// var a = function(param1) {return param1;}; function FooClass(){"use strict";}
185console.log(transformedFileData.code);
186```
187
188#### Writing a simple custom transform:
189
190```js
191/**
192 * Creates a custom transformation visitor that prefixes all calls to the
193 * `eval()` function with a call to `alert()` saying how much of a clown you are
194 * for using eval.
195 */
196var jstransform = require('jstransform');
197var utils = require('jstransform/src/utils');
198
199var Syntax = jstransform.Syntax;
200
201function visitEvalCallExpressions(traverse, node, path, state) {
202 // Appends an alert() call to the output buffer *before* the visited node
203 // (in this case the eval call) is appended to the output buffer
204 utils.append('alert("...eval?...really?...");', state);
205
206 // Now we copy the eval expression to the output buffer from the original
207 // source
208 utils.catchup(node.range[1], state);
209}
210visitEvalCallExpressions.test = function(node, path, state) {
211 return node.type === Syntax.CallExpression
212 && node.callee.type === Syntax.Identifier
213 && node.callee.name === 'eval';
214};
215
216// Normally you'd read this from the filesystem, but I'll just use a string here
217// to simplify the example.
218var originalFileContents = "eval('foo');";
219
220var transformedFileData = jstransform.transform(
221 [visitEvalCallExpressions], // Multiple visitors may be applied at once, so an
222 // array is always expected for the first argument
223 originalFileContents
224);
225
226// alert("...eval?...really?...");eval('foo');
227console.log(transformedFileData.code);
228```
229
230### Simple API
231
232#### Reading a file and applying tranforms
233
234```js
235var simple = require('jstransform/simple');
236var fs = require('fs');
237
238var originalCode = fs.readFileSync('path/to/file.js');
239
240// Apply all available ES6 transforms
241var transformed = simple.transform(originalCode, {es6: true});
242console.log(transformed.code);
243
244// Apply ES6 and ES7, generating ES3 compatible code (for IE8)
245transformed = simple.transform(originalCode, {harmony: true, target: 'es3'});
246console.log(transformed.code);
247```
248
249
250## Migration Guide
251
252### Simple API
253
254If you are coming from `react-tools` and using Node, the APIs are very similar. There are a couple important differences.
255
2561. JSX will not be tranformed by default! You must specify `react: true` in the options.
2572. The return value of `transform` is not the same. `react-tools.transform` only returned the resulting code. `simple.transform` always returns and object with a `code` property. However, if you were using `react-tools.transformWithDetails`, `simple.transform` is essentially the same.
258
259### CLI
260
261These are virtually identical but again, there are some important difference.
262
2631. JSX will not be transformed by default! You must specify `--react`.
2642. We are using a different executable - `jstransform` - (`jsx` doesn't make sense here).
2653. There are a numbr of new options available. Namely `--utility`, `--es6` and `--es7` (`--harmony` is still available and will enable both).