Skip to content
This repository has been archived by the owner on Jan 13, 2022. It is now read-only.

Commit

Permalink
Add the new API and CLI
Browse files Browse the repository at this point in the history
This mostly behaves the same way react-tools did. One big difference is
that the transform function exported does not have a simple string
return value. This is more like transformWithDetails.

This is inline with how babel does it, and I like it. We already have
the information, we might as well expose it and leave it to the consumer
to get what it wants off.
  • Loading branch information
zpao committed Apr 6, 2015
1 parent 9bea9ee commit b83e9c2
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 0 deletions.
3 changes: 3 additions & 0 deletions bin/jstransform
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env node

require('../src/cli');
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"email": "jeffmo@fb.com"
}
],
"bin": "bin/jstransform",
"main": "src/jstransform",
"repository": {
"type": "git",
Expand All @@ -21,6 +22,7 @@
],
"dependencies": {
"base62": "0.1.1",
"commoner": "^0.10.1",
"esprima-fb": "^14001.1.0-dev-harmony-fb",
"source-map": "0.1.31"
},
Expand Down
2 changes: 2 additions & 0 deletions simple.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Just re-export the simple API. This will eventually go away. require('jstransform') will give the simple API and the current API will be moved to something else (perhaps 'jstranform/advanced')
module.exports = require('./src/simple');
56 changes: 56 additions & 0 deletions src/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
var transform = require('./simple').transform;

require('commoner').version(
require('../package.json').version
).resolve(function(id) {
return this.readModuleP(id);
}).option(
'--react',
'Turns on the React JSX and React displayName transforms'
).option(
'--harmony',
'Turns on JS transformations such as ES6 Classes etc.'
).option(
'--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".',
'es5'
).option(
'--strip-types',
'Strips out type annotations.'
).option(
'--es6module',
'Parses the file as a valid ES6 module. ' +
'(Note that this means implicit strict mode)'
).option(
'--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)'
).option(
'--source-map-inline',
'Embed inline sourcemap in transformed source'
).process(function(id, source) {
// This is where JSX, ES6, etc. desugaring happens.
// We don't do any pre-processing of options so that the command line and the
// JS API both expose the same set of options. We do extract the options that
// we care about from commoner though so we aren't passing too many things
// along.
// var options = {
// harmony: this.options.harmony,
// sourceMap: this.options.sourceMapInline,
// stripTypes: this.options.stripTypes,
// es6module: this.options.es6module,
// nonStrictEs6module: this.options.nonStrictEs6module,
// target: this.options.target
// };
// return transform(source, options).code;
// console.log(source, this.options);
// return '';
var result = transform(source, this.options);

return this.options.sourceMapInline ? result.sourceMapInline : result.code;
});

27 changes: 27 additions & 0 deletions src/inline-source-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Copyright 2013-2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

'use strict';
/*eslint-disable no-undef*/
var Buffer = require('buffer').Buffer;

function inlineSourceMap(sourceMap, sourceCode, sourceFilename) {
// This can be used with a sourcemap that has already has toJSON called on it.
// Check first.
var json = sourceMap;
if (typeof sourceMap.toJSON === 'function') {
json = sourceMap.toJSON();
}
json.sources = [sourceFilename];
json.sourcesContent = [sourceCode];
var base64 = Buffer(JSON.stringify(json)).toString('base64');
return '//# sourceMappingURL=data:application/json;base64,' + base64;
}

module.exports = inlineSourceMap;
185 changes: 185 additions & 0 deletions src/simple.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/**
* Copyright 2013-2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

'use strict';
/*eslint-disable no-undef*/
var visitors = require('../visitors');
var jstransform = require('./jstransform');
var typesSyntax = require('../visitors/type-syntax');
var inlineSourceMap = require('./inline-source-map');

var fs = require('fs');

/**
* Transforms the given code with the given options.
*
* @param {string} code
* @param {object} options
* @return {object}
*/
function transform(code, options) {
// Process options
var transformOptions = {};

// transformOptions.harmony = options.harmony;
// transformOptions.stripTypes = options.stripTypes;
// transformOptions.sourceMap = options.sourceMap;
transformOptions.filename = options.sourceFilename;

if (options.es6module) {
transformOptions.sourceType = 'module';
}
if (options.nonStrictEs6module) {
transformOptions.sourceType = 'nonStrictModule';
}

// Instead of doing any fancy validation, only look for 'es3'. If we have
// that, then use it. Otherwise use 'es5'.
transformOptions.es3 = options.target === 'es3';
transformOptions.es5 = !transformOptions.es3;

// Determine visitors to use
var visitorSets = [];

if (options.react) {
visitorSets.push('react');
}

if (options.harmony) {
visitorSets.push('harmony');
}

if (options.es6) {
visitorSets.push('es6');
}

if (options.es7) {
visitorSets.push('es7');
}

if (transformOptions.es3) {
visitorSets.push('target:es3');
}


if (options.stripTypes) {
// Stripping types needs to happen before the other transforms
// unfortunately, due to bad interactions. For example,
// es6-rest-param-visitors conflict with stripping rest param type
// annotation
code = jstransform.transform(
typesSyntax.visitorList,
code,
transformOptions
).code;
}

var visitorList = visitors.getVisitorsBySet(visitorSets);
// var result = 'code';
// console.log(code, visitorList);
var result = jstransform.transform(visitorList, code, transformOptions);
//
// TODO: Handle sourcemap processing
if (options.sourceMapInline) {
result.inlineSourceMap = inlineSourceMap(
result.sourceMap,
code,
options.fileName
);
}

return result;
}

function transformFile(file, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}

fs.readFile(file, 'utf-8', function(err, contents) {
if (err) {
return callback(err, null);
}

var result = transform(contents, options);
callback(result);
});
}

function transformFileSync(file, options) {
var contents = fs.readFileSync(file, 'utf-8');
return transform(contents, options);
}

module.exports = {
transform: transform,
transformFile: transformFile,
transformFileSync: transformFileSync
};

// module.exports = {
// transform: function(input, options) {
// options = processOptions(options);
// var output = innerTransform(input, options);
// var result = output.code;
// if (options.sourceMap) {
// var map = inlineSourceMap(
// output.sourceMap,
// input,
// options.filename
// );
// result += '\n' + map;
// }
// return result;
// },
// transformWithDetails: function(input, options) {
// options = processOptions(options);
// var output = innerTransform(input, options);
// var result = {};
// result.code = output.code;
// if (options.sourceMap) {
// result.sourceMap = output.sourceMap.toJSON();
// }
// if (options.filename) {
// result.sourceMap.sources = [options.filename];
// }
// return result;
// }
// };
//
// /**
// * Only copy the values that we need. We'll do some preprocessing to account for
// * converting command line flags to options that jstransform can actually use.
// */
// function processOptions(opts) {
//
// }
//
// function innerTransform(input, options) {
// var visitorSets = ['react'];
// if (options.harmony) {
// visitorSets.push('harmony');
// }
//
// if (options.es3) {
// visitorSets.push('es3');
// }
//
// if (options.stripTypes) {
// // Stripping types needs to happen before the other transforms
// // unfortunately, due to bad interactions. For example,
// // es6-rest-param-visitors conflict with stripping rest param type
// // annotation
// input = transform(typesSyntax.visitorList, input, options).code;
// }
//
// var visitorList = visitors.getVisitorsBySet(visitorSets);
// return transform(visitorList, input, options);
// }

0 comments on commit b83e9c2

Please sign in to comment.