mirror of
https://github.com/zebrajr/react.git
synced 2026-01-15 12:15:22 +00:00
Move to using jstransform and esprima-fb npm modules
This commit is contained in:
2
bin/jsx
2
bin/jsx
@@ -2,7 +2,7 @@
|
||||
"use strict";
|
||||
|
||||
var visitors = require('../vendor/fbtransform/visitors').transformVisitors;
|
||||
var transform = require('../vendor/fbtransform/lib/transform').transform;
|
||||
var transform = require('jstransform').transform;
|
||||
var propagate = require("../vendor/constants").propagate;
|
||||
|
||||
require("commoner").resolve(function(id) {
|
||||
|
||||
2
main.js
2
main.js
@@ -2,7 +2,7 @@
|
||||
|
||||
var React = require('./build/modules/React');
|
||||
var visitors = require('./vendor/fbtransform/visitors').transformVisitors;
|
||||
var transform = require('./vendor/fbtransform/lib/transform').transform;
|
||||
var transform = require('jstransform').transform;
|
||||
|
||||
module.exports = {
|
||||
React: React,
|
||||
|
||||
@@ -35,11 +35,10 @@
|
||||
"test": "grunt build && grunt test"
|
||||
},
|
||||
"dependencies": {
|
||||
"base62": "~0.1.1",
|
||||
"commoner": "~0.8.4",
|
||||
"esprima": "https://github.com/facebook/esprima/tarball/a3e0ea3979eb8d54d8bfade220c272903f928b1e",
|
||||
"recast": "~0.4.8",
|
||||
"source-map": "~0.1.22"
|
||||
"esprima-fb": "1001.1001.1000-dev-harmony-fb",
|
||||
"jstransform": "~1.0.0",
|
||||
"recast": "~0.4.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"browserify": "~2.24.1",
|
||||
|
||||
4
vendor/browser-transforms.js
vendored
4
vendor/browser-transforms.js
vendored
@@ -20,10 +20,10 @@
|
||||
var runScripts;
|
||||
var headEl;
|
||||
|
||||
var transform = require('./fbtransform/lib/transform').transform;
|
||||
var transform = require('jstransform').transform;
|
||||
var visitors = require('./fbtransform/visitors').transformVisitors;
|
||||
var transform = transform.bind(null, visitors.react);
|
||||
var docblock = require('./fbtransform/lib/docblock');
|
||||
var docblock = require('jstransform/src/docblock');
|
||||
|
||||
|
||||
exports.transform = transform;
|
||||
|
||||
86
vendor/fbtransform/lib/docblock.js
vendored
86
vendor/fbtransform/lib/docblock.js
vendored
@@ -1,86 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var docblockRe = /^\s*(\/\*\*(.|\n)*?\*\/)/;
|
||||
var ltrimRe = /^\s*/;
|
||||
/**
|
||||
* @param {String} contents
|
||||
* @return {String}
|
||||
*/
|
||||
function extract(contents) {
|
||||
var match = contents.match(docblockRe);
|
||||
if (match) {
|
||||
return match[0].replace(ltrimRe, '') || '';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
var commentStartRe = /^\/\*\*?/;
|
||||
var commentEndRe = /\*\/$/;
|
||||
var wsRe = /[\t ]+/g;
|
||||
var stringStartRe = /(\n|^) *\*/g;
|
||||
var multilineRe = /(?:^|\n) *(@[^\n]*?) *\n *([^@\n\s][^@\n]+?) *\n/g;
|
||||
var propertyRe = /(?:^|\n) *@(\S+) *([^\n]*)/g;
|
||||
|
||||
/**
|
||||
* @param {String} contents
|
||||
* @return {Array}
|
||||
*/
|
||||
function parse(docblock) {
|
||||
docblock = docblock
|
||||
.replace(commentStartRe, '')
|
||||
.replace(commentEndRe, '')
|
||||
.replace(wsRe, ' ')
|
||||
.replace(stringStartRe, '$1');
|
||||
|
||||
// Normalize multi-line directives
|
||||
var prev = '';
|
||||
while (prev != docblock) {
|
||||
prev = docblock;
|
||||
docblock = docblock.replace(multilineRe, "\n$1 $2\n");
|
||||
}
|
||||
docblock = docblock.trim();
|
||||
|
||||
var result = [];
|
||||
var match;
|
||||
while (match = propertyRe.exec(docblock)) {
|
||||
result.push([match[1], match[2]]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as parse but returns an object of prop: value instead of array of paris
|
||||
* If a property appers more than once the last one will be returned
|
||||
*
|
||||
* @param {String} contents
|
||||
* @return {Object}
|
||||
*/
|
||||
function parseAsObject(docblock) {
|
||||
var pairs = parse(docblock);
|
||||
var result = {};
|
||||
for (var i = 0; i < pairs.length; i++) {
|
||||
result[pairs[i][0]] = pairs[i][1];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
exports.extract = extract;
|
||||
exports.parse = parse;
|
||||
exports.parseAsObject = parseAsObject;
|
||||
141
vendor/fbtransform/lib/transform.js
vendored
141
vendor/fbtransform/lib/transform.js
vendored
@@ -1,141 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*global exports:true*/
|
||||
/*jslint node: true*/
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Syntax transfomer for javascript. Takes the source in, spits the source
|
||||
* out. Tries to maintain readability and preserve whitespace and line numbers
|
||||
* where posssible.
|
||||
*
|
||||
* Support
|
||||
* - ES6 class transformation + private property munging, see ./classes.js
|
||||
* - React XHP style syntax transformations, see ./react.js
|
||||
* - Bolt XHP style syntax transformations, see ./bolt.js
|
||||
*
|
||||
* The general flow is the following:
|
||||
* - Parse the source with our customized esprima-parser
|
||||
* https://github.com/voloko/esprima. We have to customize the parser to
|
||||
* support non-standard XHP-style syntax. We parse the source range: true
|
||||
* option that forces esprima to return positions in the source within
|
||||
* resulting parse tree.
|
||||
*
|
||||
* - Traverse resulting syntax tree, trying to apply a set of visitors to each
|
||||
* node. Each visitor should provide a .test() function that tests if the
|
||||
* visitor can process a given node.
|
||||
*
|
||||
* - Visitor is responsible for code generation for a given syntax node.
|
||||
* Generated code is stored in state.g.buffer that is passed to every
|
||||
* visitor. It's up to the visitor to process the code the way it sees fit.
|
||||
* All of the current visitors however use both the node and the original
|
||||
* source to generate transformed code. They use nodes to generate new
|
||||
* code and they copy the original source, preserving whitespace and comments,
|
||||
* for the parts they don't care about.
|
||||
*/
|
||||
var esprima = require('esprima');
|
||||
|
||||
var createState = require('./utils').createState;
|
||||
var catchup = require('./utils').catchup;
|
||||
|
||||
/**
|
||||
* @param {object} object
|
||||
* @param {function} visitor
|
||||
* @param {array} path
|
||||
* @param {object} state
|
||||
*/
|
||||
function traverse(object, path, state) {
|
||||
var key, child;
|
||||
|
||||
if (walker(traverse, object, path, state) === false) {
|
||||
return;
|
||||
}
|
||||
path.unshift(object);
|
||||
for (key in object) {
|
||||
// skip obviously wrong attributes
|
||||
if (key === 'range' || key === 'loc') {
|
||||
continue;
|
||||
}
|
||||
if (object.hasOwnProperty(key)) {
|
||||
child = object[key];
|
||||
if (typeof child === 'object' && child !== null) {
|
||||
child.range && catchup(child.range[0], state);
|
||||
traverse(child, path, state);
|
||||
child.range && catchup(child.range[1], state);
|
||||
}
|
||||
}
|
||||
}
|
||||
path.shift();
|
||||
}
|
||||
|
||||
function walker(traverse, object, path, state) {
|
||||
var visitors = state.g.visitors;
|
||||
for (var i = 0; i < visitors.length; i++) {
|
||||
if (visitors[i].test(object, path, state)) {
|
||||
return visitors[i](traverse, object, path, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function runPass(source, visitors, options) {
|
||||
var ast;
|
||||
try {
|
||||
ast = esprima.parse(source, { comment: true, loc: true, range: true });
|
||||
} catch (e) {
|
||||
e.message = 'Parse Error: ' + e.message;
|
||||
throw e;
|
||||
}
|
||||
var state = createState(source, options);
|
||||
state.g.originalProgramAST = ast;
|
||||
state.g.visitors = visitors;
|
||||
|
||||
if (options.sourceMap) {
|
||||
var SourceMapGenerator = require('source-map').SourceMapGenerator;
|
||||
state.g.sourceMap = new SourceMapGenerator({ file: 'transformed.js' });
|
||||
}
|
||||
traverse(ast, [], state);
|
||||
catchup(source.length, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies all available transformations to the source
|
||||
* @param {array} visitors
|
||||
* @param {string} source
|
||||
* @param {?object} options
|
||||
* @return {object}
|
||||
*/
|
||||
function transform(visitors, source, options) {
|
||||
options = options || {};
|
||||
|
||||
var state = runPass(source, visitors, options);
|
||||
var sourceMap = state.g.sourceMap;
|
||||
|
||||
if (sourceMap) {
|
||||
return {
|
||||
sourceMap: sourceMap,
|
||||
sourceMapFilename: options.filename || 'source.js',
|
||||
code: state.g.buffer
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: state.g.buffer
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
exports.transform = transform;
|
||||
332
vendor/fbtransform/lib/utils.js
vendored
332
vendor/fbtransform/lib/utils.js
vendored
@@ -1,332 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*global exports:true*/
|
||||
|
||||
/**
|
||||
* State represents the given parser state. It has a local and global parts.
|
||||
* Global contains parser position, source, etc. Local contains scope based
|
||||
* properties, like current class name. State should contain all the info
|
||||
* required for transformation. It's the only mandatory object that is being
|
||||
* passed to every function in transform chain.
|
||||
*
|
||||
* @param {String} source
|
||||
* @param {Object} transformOptions
|
||||
* @return {Object}
|
||||
*/
|
||||
function createState(source, transformOptions) {
|
||||
return {
|
||||
/**
|
||||
* Name of the super class variable
|
||||
* @type {String}
|
||||
*/
|
||||
superVar: '',
|
||||
/**
|
||||
* Name of the enclosing class scope
|
||||
* @type {String}
|
||||
*/
|
||||
scopeName: '',
|
||||
/**
|
||||
* Global state (not affected by updateState)
|
||||
* @type {Object}
|
||||
*/
|
||||
g: {
|
||||
/**
|
||||
* A set of general options that transformations can consider while doing
|
||||
* a transformation:
|
||||
*
|
||||
* - minify
|
||||
* Specifies that transformation steps should do their best to minify
|
||||
* the output source when possible. This is useful for places where
|
||||
* minification optimizations are possible with higher-level context
|
||||
* info than what jsxmin can provide.
|
||||
*
|
||||
* For example, the ES6 class transform will minify munged private
|
||||
* variables if this flag is set.
|
||||
*/
|
||||
opts: transformOptions,
|
||||
/**
|
||||
* Current position in the source code
|
||||
* @type {Number}
|
||||
*/
|
||||
position: 0,
|
||||
/**
|
||||
* Buffer containing the result
|
||||
* @type {String}
|
||||
*/
|
||||
buffer: '',
|
||||
/**
|
||||
* Indentation offset (only negative offset is supported now)
|
||||
* @type {Number}
|
||||
*/
|
||||
indentBy: 0,
|
||||
/**
|
||||
* Source that is being transformed
|
||||
* @type {String}
|
||||
*/
|
||||
source: source,
|
||||
|
||||
/**
|
||||
* Cached parsed docblock (see getDocblock)
|
||||
* @type {object}
|
||||
*/
|
||||
docblock: null,
|
||||
|
||||
/**
|
||||
* Whether the thing was used
|
||||
* @type {Boolean}
|
||||
*/
|
||||
tagNamespaceUsed: false,
|
||||
|
||||
/**
|
||||
* If using bolt xjs transformation
|
||||
* @type {Boolean}
|
||||
*/
|
||||
isBolt: undefined,
|
||||
|
||||
/**
|
||||
* Whether to record source map (expensive) or not
|
||||
* @type {SourceMapGenerator|null}
|
||||
*/
|
||||
sourceMap: null,
|
||||
|
||||
/**
|
||||
* Filename of the file being processed. Will be returned as a source
|
||||
* attribute in the source map
|
||||
*/
|
||||
sourceMapFilename: 'source.js',
|
||||
|
||||
/**
|
||||
* Only when source map is used: last line in the source for which
|
||||
* source map was generated
|
||||
* @type {Number}
|
||||
*/
|
||||
sourceLine: 1,
|
||||
|
||||
/**
|
||||
* Only when source map is used: last line in the buffer for which
|
||||
* source map was generated
|
||||
* @type {Number}
|
||||
*/
|
||||
bufferLine: 1,
|
||||
|
||||
/**
|
||||
* The top-level Program AST for the original file.
|
||||
*/
|
||||
originalProgramAST: null,
|
||||
|
||||
sourceColumn: 0,
|
||||
bufferColumn: 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a copy of a given state with "update" and returns an updated state.
|
||||
*
|
||||
* @param {Object} state
|
||||
* @param {Object} update
|
||||
* @return {Object}
|
||||
*/
|
||||
function updateState(state, update) {
|
||||
return {
|
||||
g: state.g,
|
||||
superVar: update.superVar || state.superVar,
|
||||
scopeName: update.scopeName || state.scopeName
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a state fill the resulting buffer from the original source up to
|
||||
* the end
|
||||
* @param {Number} end
|
||||
* @param {Object} state
|
||||
* @param {Function?} contentTransformer Optional callback to transform newly
|
||||
* added content.
|
||||
*/
|
||||
function catchup(end, state, contentTransformer) {
|
||||
if (end < state.g.position) {
|
||||
// cannot move backwards
|
||||
return;
|
||||
}
|
||||
var source = state.g.source.substring(state.g.position, end);
|
||||
var transformed = updateIndent(source, state);
|
||||
if (state.g.sourceMap && transformed) {
|
||||
// record where we are
|
||||
state.g.sourceMap.addMapping({
|
||||
generated: { line: state.g.bufferLine, column: state.g.bufferColumn },
|
||||
original: { line: state.g.sourceLine, column: state.g.sourceColumn },
|
||||
source: state.g.sourceMapFilename
|
||||
});
|
||||
|
||||
// record line breaks in transformed source
|
||||
var sourceLines = source.split('\n');
|
||||
var transformedLines = transformed.split('\n');
|
||||
// Add line break mappings between last known mapping and the end of the
|
||||
// added piece. So for the code piece
|
||||
// (foo, bar);
|
||||
// > var x = 2;
|
||||
// > var b = 3;
|
||||
// var c =
|
||||
// only add lines marked with ">": 2, 3.
|
||||
for (var i = 1; i < sourceLines.length - 1; i++) {
|
||||
state.g.sourceMap.addMapping({
|
||||
generated: { line: state.g.bufferLine, column: 0 },
|
||||
original: { line: state.g.sourceLine, column: 0 },
|
||||
source: state.g.sourceMapFilename
|
||||
});
|
||||
state.g.sourceLine++;
|
||||
state.g.bufferLine++;
|
||||
}
|
||||
// offset for the last piece
|
||||
if (sourceLines.length > 1) {
|
||||
state.g.sourceLine++;
|
||||
state.g.bufferLine++;
|
||||
state.g.sourceColumn = 0;
|
||||
state.g.bufferColumn = 0;
|
||||
}
|
||||
state.g.sourceColumn += sourceLines[sourceLines.length - 1].length;
|
||||
state.g.bufferColumn +=
|
||||
transformedLines[transformedLines.length - 1].length;
|
||||
}
|
||||
state.g.buffer +=
|
||||
contentTransformer ? contentTransformer(transformed) : transformed;
|
||||
state.g.position = end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies `catchup` but passing in a function that removes any non-whitespace
|
||||
* characters.
|
||||
*/
|
||||
var re = /(\S)/g;
|
||||
function stripNonWhite(value) {
|
||||
return value.replace(re, function() {
|
||||
return '';
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Catches up as `catchup` but turns each non-white character into a space.
|
||||
*/
|
||||
function catchupWhiteSpace(end, state) {
|
||||
catchup(end, state, stripNonWhite);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as catchup but does not touch the buffer
|
||||
* @param {Number} end
|
||||
* @param {Object} state
|
||||
*/
|
||||
function move(end, state) {
|
||||
// move the internal cursors
|
||||
if (state.g.sourceMap) {
|
||||
if (end < state.g.position) {
|
||||
state.g.position = 0;
|
||||
state.g.sourceLine = 1;
|
||||
state.g.sourceColumn = 0;
|
||||
}
|
||||
|
||||
var source = state.g.source.substring(state.g.position, end);
|
||||
var sourceLines = source.split('\n');
|
||||
if (sourceLines.length > 1) {
|
||||
state.g.sourceLine += sourceLines.length - 1;
|
||||
state.g.sourceColumn = 0;
|
||||
}
|
||||
state.g.sourceColumn += sourceLines[sourceLines.length - 1].length;
|
||||
}
|
||||
state.g.position = end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a string of text to the buffer
|
||||
* @param {String} string
|
||||
* @param {Object} state
|
||||
*/
|
||||
function append(string, state) {
|
||||
if (state.g.sourceMap && string) {
|
||||
state.g.sourceMap.addMapping({
|
||||
generated: { line: state.g.bufferLine, column: state.g.bufferColumn },
|
||||
original: { line: state.g.sourceLine, column: state.g.sourceColumn },
|
||||
source: state.g.sourceMapFilename
|
||||
});
|
||||
var transformedLines = string.split('\n');
|
||||
if (transformedLines.length > 1) {
|
||||
state.g.bufferLine += transformedLines.length - 1;
|
||||
state.g.bufferColumn = 0;
|
||||
}
|
||||
state.g.bufferColumn +=
|
||||
transformedLines[transformedLines.length - 1].length;
|
||||
}
|
||||
state.g.buffer += string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update indent using state.indentBy property. Indent is measured in
|
||||
* double spaces. Updates a single line only.
|
||||
*
|
||||
* @param {String} str
|
||||
* @param {Object} state
|
||||
* @return {String}
|
||||
*/
|
||||
function updateIndent(str, state) {
|
||||
for (var i = 0; i < -state.g.indentBy; i++) {
|
||||
str = str.replace(/(^|\n)( {2}|\t)/g, '$1');
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates indent from the beginning of the line until "start" or the first
|
||||
* character before start.
|
||||
* @example
|
||||
* " foo.bar()"
|
||||
* ^
|
||||
* start
|
||||
* indent will be 2
|
||||
*
|
||||
* @param {Number} start
|
||||
* @param {Object} state
|
||||
* @return {Number}
|
||||
*/
|
||||
function indentBefore(start, state) {
|
||||
var end = start;
|
||||
start = start - 1;
|
||||
|
||||
while (start > 0 && state.g.source[start] != '\n') {
|
||||
if (!state.g.source[start].match(/[ \t]/)) {
|
||||
end = start;
|
||||
}
|
||||
start--;
|
||||
}
|
||||
return state.g.source.substring(start + 1, end);
|
||||
}
|
||||
|
||||
function getDocblock(state) {
|
||||
if (!state.g.docblock) {
|
||||
var docblock = require('./docblock');
|
||||
state.g.docblock =
|
||||
docblock.parseAsObject(docblock.extract(state.g.source));
|
||||
}
|
||||
return state.g.docblock;
|
||||
}
|
||||
|
||||
exports.catchup = catchup;
|
||||
exports.catchupWhiteSpace = catchupWhiteSpace;
|
||||
exports.append = append;
|
||||
exports.move = move;
|
||||
exports.updateIndent = updateIndent;
|
||||
exports.indentBefore = indentBefore;
|
||||
exports.updateState = updateState;
|
||||
exports.createState = createState;
|
||||
exports.getDocblock = getDocblock;
|
||||
2
vendor/fbtransform/syntax.js
vendored
2
vendor/fbtransform/syntax.js
vendored
@@ -3,7 +3,7 @@
|
||||
/*global exports:true*/
|
||||
"use strict";
|
||||
|
||||
var transform = require('./lib/transform').transform;
|
||||
var transform = require('jstransform').transform;
|
||||
var visitors = require('./visitors');
|
||||
|
||||
/**
|
||||
|
||||
492
vendor/fbtransform/transforms/classes.js
vendored
492
vendor/fbtransform/transforms/classes.js
vendored
@@ -1,492 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*global exports:true*/
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Desugarizer for ES6 minimal class proposal. See
|
||||
* http://wiki.ecmascript.org/doku.php?id=harmony:proposals
|
||||
*
|
||||
* Does not require any runtime. Preserves whitespace and comments.
|
||||
* Supports a class declaration with methods, super calls and inheritance.
|
||||
* Currently does not support for getters and setters, since there's a very
|
||||
* low probability we're going to use them anytime soon.
|
||||
*
|
||||
* Additional features:
|
||||
* - Any member with private name (the name with prefix _, such _name) inside
|
||||
* the class's scope will be munged. This would will to eliminate the case
|
||||
* of sub-class accidentally overriding the super-class's provate properties
|
||||
* also discouage people from accessing private members that they should not
|
||||
* access. However, quoted property names don't get munged.
|
||||
*
|
||||
* class SkinnedMesh extends require('THREE').Mesh {
|
||||
*
|
||||
* update(camera) {
|
||||
* camera.code = 'iphone'
|
||||
* super.update(camera);
|
||||
* }
|
||||
*
|
||||
* /
|
||||
* * @constructor
|
||||
* /
|
||||
* constructor(geometry, materials) {
|
||||
* super(geometry, materials);
|
||||
*
|
||||
* super.update(1);
|
||||
*
|
||||
* this.identityMatrix = new THREE.Matrix4();
|
||||
* this.bones = [];
|
||||
* this.boneMatrices = [];
|
||||
* this._name = 'foo';
|
||||
* }
|
||||
*
|
||||
* /
|
||||
* * some other code
|
||||
* /
|
||||
* readMore() {
|
||||
*
|
||||
* }
|
||||
*
|
||||
* _doSomething() {
|
||||
*
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* should be converted to
|
||||
*
|
||||
* var SkinnedMesh = (function() {
|
||||
* var __super = require('parent').Mesh;
|
||||
*
|
||||
* /
|
||||
* * @constructor
|
||||
* /
|
||||
* function SkinnedMesh(geometry, materials) {
|
||||
* __super.call(this, geometry, materials);
|
||||
*
|
||||
* __super.prototype.update.call(this, 1);
|
||||
*
|
||||
* this.identityMatrix = new THREE.Matrix4();
|
||||
* this.bones = [];
|
||||
* this.boneMatrices = [];
|
||||
* this.$SkinnedMesh_name = 'foo';
|
||||
* }
|
||||
* SkinnedMesh.prototype = Object.create(__super.prototype);
|
||||
* SkinnedMesh.prototype.constructor = SkinnedMesh;
|
||||
*
|
||||
* /
|
||||
* * @param camera
|
||||
* /
|
||||
* SkinnedMesh.prototype.update = function(camera) {
|
||||
* camera.code = 'iphone'
|
||||
* __super.prototype.update.call(this, camera);
|
||||
* };
|
||||
*
|
||||
* SkinnedMesh.prototype.readMore = function() {
|
||||
*
|
||||
* };
|
||||
*
|
||||
* SkinnedMesh.prototype.$SkinnedMesh_doSomething = function() {
|
||||
*
|
||||
* };
|
||||
*
|
||||
* return SkinnedMesh;
|
||||
* })();
|
||||
*
|
||||
*/
|
||||
var Syntax = require('esprima').Syntax;
|
||||
var base62 = require('base62');
|
||||
|
||||
var catchup = require('../lib/utils').catchup;
|
||||
var append = require('../lib/utils').append;
|
||||
var move = require('../lib/utils').move;
|
||||
var indentBefore = require('../lib/utils').indentBefore;
|
||||
var updateIndent = require('../lib/utils').updateIndent;
|
||||
var updateState = require('../lib/utils').updateState;
|
||||
|
||||
function findConstructorIndex(object) {
|
||||
var classElements = object.body && object.body.body || [];
|
||||
for (var i = 0; i < classElements.length; i++) {
|
||||
if (classElements[i].type === Syntax.MethodDefinition &&
|
||||
classElements[i].key.name === 'constructor') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
var _mungedSymbolMaps = {};
|
||||
function getMungedName(scopeName, name, minify) {
|
||||
if (minify) {
|
||||
if (!_mungedSymbolMaps[scopeName]) {
|
||||
_mungedSymbolMaps[scopeName] = {
|
||||
symbolMap: {},
|
||||
identifierUUIDCounter: 0
|
||||
};
|
||||
}
|
||||
|
||||
var symbolMap = _mungedSymbolMaps[scopeName].symbolMap;
|
||||
if (!symbolMap[name]) {
|
||||
symbolMap[name] =
|
||||
base62.encode(_mungedSymbolMaps[scopeName].identifierUUIDCounter);
|
||||
_mungedSymbolMaps[scopeName].identifierUUIDCounter++;
|
||||
}
|
||||
name = symbolMap[name];
|
||||
}
|
||||
return '$' + scopeName + name;
|
||||
}
|
||||
|
||||
function shouldMungeName(scopeName, name, state) {
|
||||
// only run when @preventMunge is not present in the docblock
|
||||
if (state.g.preventMunge === undefined) {
|
||||
var docblock = require('../lib/docblock');
|
||||
state.g.preventMunge = docblock.parseAsObject(
|
||||
docblock.extract(state.g.source)).preventMunge !== undefined;
|
||||
}
|
||||
// Starts with only a single underscore (i.e. don't count double-underscores)
|
||||
return !state.g.preventMunge && scopeName ? /^_(?!_)/.test(name) : false;
|
||||
}
|
||||
|
||||
|
||||
function getProtoOfPrototypeVariableName(superVar) {
|
||||
return superVar + 'ProtoOfPrototype';
|
||||
}
|
||||
|
||||
function getSuperKeyName(superVar) {
|
||||
return superVar + 'Key';
|
||||
}
|
||||
|
||||
function getSuperProtoOfPrototypeVariable(superVariableName, indent) {
|
||||
var string = (indent +
|
||||
'var $proto = $superName && $superName.prototype ? ' +
|
||||
'$superName.prototype : $superName;\n'
|
||||
).replace(/\$proto/g, getProtoOfPrototypeVariableName(superVariableName))
|
||||
.replace(/\$superName/g, superVariableName);
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
function getInheritanceSetup(superClassToken, className, indent, superName) {
|
||||
var string = '';
|
||||
if (superClassToken) {
|
||||
string += getStaticMethodsOnConstructorSetup(className, indent, superName);
|
||||
string += getPrototypeOnConstructorSetup(className, indent, superName);
|
||||
string += getConstructorPropertySetup(className, indent);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
function getStaticMethodsOnConstructorSetup(className, indent, superName) {
|
||||
var string = ( indent +
|
||||
'for (var $keyName in $superName) {\n' + indent +
|
||||
' if ($superName.hasOwnProperty($keyName)) {\n' + indent +
|
||||
' $className[$keyName] = $superName[$keyName];\n' + indent +
|
||||
' }\n' + indent +
|
||||
'}\n')
|
||||
.replace(/\$className/g, className)
|
||||
.replace(/\$keyName/g, getSuperKeyName(superName))
|
||||
.replace(/\$superName/g, superName);
|
||||
return string;
|
||||
}
|
||||
|
||||
function getPrototypeOnConstructorSetup(className, indent, superName) {
|
||||
var string = ( indent +
|
||||
'$className.prototype = Object.create($protoPrototype);\n')
|
||||
.replace(/\$protoPrototype/g, getProtoOfPrototypeVariableName(superName))
|
||||
.replace(/\$className/g, className);
|
||||
return string;
|
||||
}
|
||||
|
||||
function getConstructorPropertySetup(className, indent) {
|
||||
var string = ( indent +
|
||||
'$className.prototype.constructor = $className;\n')
|
||||
.replace(/\$className/g, className);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
function getSuperConstructorSetup(superClassToken, indent, superName) {
|
||||
if (!superClassToken) return '';
|
||||
var string = ( '\n' + indent +
|
||||
' if ($superName && $superName.prototype) {\n' + indent +
|
||||
' $superName.apply(this, arguments);\n' + indent +
|
||||
' }\n' + indent)
|
||||
.replace(/\$superName/g, superName);
|
||||
return string;
|
||||
}
|
||||
|
||||
function getMemberFunctionCall(superVar, propertyName, superArgs) {
|
||||
var string = (
|
||||
'$superPrototype.$propertyName.call($superArguments)')
|
||||
.replace(/\$superPrototype/g, getProtoOfPrototypeVariableName(superVar))
|
||||
.replace(/\$propertyName/g, propertyName)
|
||||
.replace(/\$superArguments/g, superArgs);
|
||||
return string;
|
||||
}
|
||||
|
||||
function getCallParams(classElement, state) {
|
||||
var params = classElement.value.params;
|
||||
if (!params.length) {
|
||||
return '';
|
||||
}
|
||||
return state.g.source.substring(
|
||||
params[0].range[0],
|
||||
params[params.length - 1].range[1]);
|
||||
}
|
||||
|
||||
function getSuperArguments(callExpression, state) {
|
||||
var args = callExpression.arguments;
|
||||
if (!args.length) {
|
||||
return 'this';
|
||||
}
|
||||
return 'this, ' + state.g.source.substring(
|
||||
args[0].range[0],
|
||||
args[args.length - 1].range[1]);
|
||||
}
|
||||
|
||||
// The seed is used to generate the name for an anonymous class,
|
||||
// and this seed should be unique per browser's session.
|
||||
// The value of the seed looks like this: 1229588505.2969012.
|
||||
var classIDSeed = Date.now() % (60 * 60 * 1000) + Math.random();
|
||||
|
||||
/**
|
||||
* Generates a name for an anonymous class. The generated value looks like
|
||||
* this: "Classkc6pcn_mniza1yvi"
|
||||
* @param {String} scopeName
|
||||
* @return {string} the scope name for Anonymous Class
|
||||
*/
|
||||
function generateAnonymousClassName(scopeName) {
|
||||
classIDSeed++;
|
||||
return 'Class' +
|
||||
(classIDSeed).toString(36).replace('.', '_') +
|
||||
(scopeName || '');
|
||||
}
|
||||
|
||||
function renderMethods(traverse, object, name, path, state) {
|
||||
var classElements = object.body && object.body.body || [];
|
||||
|
||||
move(object.body.range[0] + 1, state);
|
||||
for (var i = 0; i < classElements.length; i++) {
|
||||
if (classElements[i].key.name !== 'constructor') {
|
||||
catchup(classElements[i].range[0], state);
|
||||
|
||||
var memberName = classElements[i].key.name;
|
||||
if (shouldMungeName(state.scopeName, memberName, state)) {
|
||||
memberName = getMungedName(
|
||||
state.scopeName,
|
||||
memberName,
|
||||
state.g.opts.minify
|
||||
);
|
||||
}
|
||||
|
||||
var prototypeOrStatic;
|
||||
if (classElements[i]['static']) {
|
||||
prototypeOrStatic = '';
|
||||
} else {
|
||||
prototypeOrStatic = 'prototype.';
|
||||
}
|
||||
|
||||
append(name + '.' + prototypeOrStatic + memberName + ' = ', state);
|
||||
renderMethod(traverse, classElements[i], null, path, state);
|
||||
append(';', state);
|
||||
}
|
||||
move(classElements[i].range[1], state);
|
||||
}
|
||||
if (classElements.length) {
|
||||
append('\n', state);
|
||||
}
|
||||
move(object.range[1], state);
|
||||
}
|
||||
|
||||
function renderMethod(traverse, method, name, path, state) {
|
||||
append(name ? 'function ' + name + '(' : 'function(', state);
|
||||
append(getCallParams(method, state) + ') {', state);
|
||||
move(method.value.body.range[0] + 1, state);
|
||||
traverse(method.value.body, path, state);
|
||||
catchup(method.value.body.range[1] - 1, state);
|
||||
append('}', state);
|
||||
}
|
||||
|
||||
function renderSuperClass(traverse, superClass, path, state) {
|
||||
append('var ' + state.superVar + ' = ', state);
|
||||
move(superClass.range[0], state);
|
||||
traverse(superClass, path, state);
|
||||
catchup(superClass.range[1], state);
|
||||
append(';\n', state);
|
||||
}
|
||||
|
||||
function renderConstructor(traverse, object, name, indent, path, state) {
|
||||
var classElements = object.body && object.body.body || [];
|
||||
var constructorIndex = findConstructorIndex(object);
|
||||
var constructor = constructorIndex === -1 ?
|
||||
null :
|
||||
classElements[constructorIndex];
|
||||
if (constructor) {
|
||||
move(constructorIndex === 0 ?
|
||||
object.body.range[0] + 1 :
|
||||
classElements[constructorIndex - 1].range[1], state);
|
||||
catchup(constructor.range[0], state);
|
||||
renderMethod(traverse, constructor, name, path, state);
|
||||
append('\n', state);
|
||||
} else {
|
||||
if (object.superClass) {
|
||||
append('\n' + indent, state);
|
||||
}
|
||||
append('function ', state);
|
||||
if (object.id) {
|
||||
move(object.id.range[0], state);
|
||||
}
|
||||
append(name, state);
|
||||
if (object.id) {
|
||||
move(object.id.range[1], state);
|
||||
}
|
||||
append('(){ ', state);
|
||||
if (object.body) {
|
||||
move(object.body.range[0], state);
|
||||
}
|
||||
append(getSuperConstructorSetup(
|
||||
object.superClass,
|
||||
indent,
|
||||
state.superVar), state);
|
||||
append('}\n', state);
|
||||
}
|
||||
}
|
||||
|
||||
var superId = 0;
|
||||
function renderClassBody(traverse, object, path, state) {
|
||||
var name = object.id ? object.id.name : 'constructor';
|
||||
var superClass = object.superClass;
|
||||
var indent = updateIndent(
|
||||
indentBefore(object.range[0], state) + ' ',
|
||||
state);
|
||||
|
||||
state = updateState(
|
||||
state,
|
||||
{
|
||||
scopeName: object.id ? object.id.name :
|
||||
generateAnonymousClassName(state.scopeName),
|
||||
superVar: superClass ? '__super' + superId++ : ''
|
||||
});
|
||||
|
||||
// super class
|
||||
if (superClass) {
|
||||
append(indent, state);
|
||||
renderSuperClass(traverse, superClass, path, state);
|
||||
append(getSuperProtoOfPrototypeVariable(state.superVar, indent), state);
|
||||
}
|
||||
|
||||
renderConstructor(traverse, object, name, indent, path, state);
|
||||
append(getInheritanceSetup(superClass, name, indent, state.superVar), state);
|
||||
renderMethods(traverse, object, name, path, state);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
function visitClassExpression(traverse, object, path, state) {
|
||||
var indent = updateIndent(
|
||||
indentBefore(object.range[0], state) + ' ',
|
||||
state);
|
||||
var name = object.id ? object.id.name : 'constructor';
|
||||
|
||||
append('(function() {\n', state);
|
||||
renderClassBody(traverse, object, path, state);
|
||||
append(indent + 'return ' + name + ';\n', state);
|
||||
append(indent.substring(0, indent.length - 2) + '})()', state);
|
||||
return false
|
||||
}
|
||||
|
||||
visitClassExpression.test = function(object, path, state) {
|
||||
return object.type === Syntax.ClassExpression;
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
function visitClassDeclaration(traverse, object, path, state) {
|
||||
state.g.indentBy--;
|
||||
renderClassBody(traverse, object, path, state);
|
||||
state.g.indentBy++;
|
||||
return false;
|
||||
}
|
||||
|
||||
visitClassDeclaration.test = function(object, path, state) {
|
||||
return object.type === Syntax.ClassDeclaration;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
function visitSuperCall(traverse, object, path, state) {
|
||||
if (path[0].type === Syntax.CallExpression) {
|
||||
append(state.superVar +
|
||||
'.call(' + getSuperArguments(path[0], state) + ')', state);
|
||||
move(path[0].range[1], state);
|
||||
} else if (path[0].type === Syntax.MemberExpression) {
|
||||
append(getMemberFunctionCall(
|
||||
state.superVar,
|
||||
path[0].property.name,
|
||||
getSuperArguments(path[1], state)), state);
|
||||
move(path[1].range[1], state);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
visitSuperCall.test = function(object, path, state) {
|
||||
return state.superVar && object.type === Syntax.Identifier &&
|
||||
object.name === 'super';
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
function visitPrivateProperty(traverse, object, path, state) {
|
||||
var type = path[0] ? path[0].type : null;
|
||||
if (type !== Syntax.Property) {
|
||||
if (type === Syntax.MemberExpression) {
|
||||
type = path[0].object ? path[0].object.type : null;
|
||||
if (type === Syntax.Identifier &&
|
||||
path[0].object.range[0] === object.range[0]) {
|
||||
// Identifier is a variable that appears "private".
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Other syntax that are neither Property nor MemberExpression.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var oldName = object.name;
|
||||
var newName = getMungedName(
|
||||
state.scopeName,
|
||||
oldName,
|
||||
state.g.opts.minify
|
||||
);
|
||||
append(newName, state);
|
||||
move(object.range[1], state);
|
||||
}
|
||||
|
||||
visitPrivateProperty.test = function(object, path, state) {
|
||||
return object.type === Syntax.Identifier &&
|
||||
shouldMungeName(state.scopeName, object.name, state);
|
||||
};
|
||||
|
||||
|
||||
exports.visitClassDeclaration = visitClassDeclaration;
|
||||
exports.visitClassExpression = visitClassExpression;
|
||||
exports.visitSuperCall = visitSuperCall;
|
||||
exports.visitPrivateProperty = visitPrivateProperty;
|
||||
10
vendor/fbtransform/transforms/react.js
vendored
10
vendor/fbtransform/transforms/react.js
vendored
@@ -16,12 +16,12 @@
|
||||
/*global exports:true*/
|
||||
"use strict";
|
||||
|
||||
var Syntax = require('esprima').Syntax;
|
||||
var Syntax = require('esprima-fb').Syntax;
|
||||
|
||||
var catchup = require('../lib/utils').catchup;
|
||||
var append = require('../lib/utils').append;
|
||||
var move = require('../lib/utils').move;
|
||||
var getDocblock = require('../lib/utils').getDocblock;
|
||||
var catchup = require('jstransform/src/utils').catchup;
|
||||
var append = require('jstransform/src/utils').append;
|
||||
var move = require('jstransform/src/utils').move;
|
||||
var getDocblock = require('jstransform/src/utils').getDocblock;
|
||||
|
||||
var FALLBACK_TAGS = require('./xjs').knownTags;
|
||||
var renderXJSExpressionContainer =
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
/*global exports:true*/
|
||||
"use strict";
|
||||
|
||||
var Syntax = require('esprima').Syntax;
|
||||
var catchup = require('../lib/utils').catchup;
|
||||
var append = require('../lib/utils').append;
|
||||
var getDocblock = require('../lib/utils').getDocblock;
|
||||
var Syntax = require('esprima-fb').Syntax;
|
||||
var catchup = require('jstransform/src/utils').catchup;
|
||||
var append = require('jstransform/src/utils').append;
|
||||
var getDocblock = require('jstransform/src/utils').getDocblock;
|
||||
|
||||
/**
|
||||
* Transforms the following:
|
||||
|
||||
8
vendor/fbtransform/transforms/xjs.js
vendored
8
vendor/fbtransform/transforms/xjs.js
vendored
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
/*global exports:true*/
|
||||
"use strict";
|
||||
var append = require('../lib/utils').append;
|
||||
var catchup = require('../lib/utils').catchup;
|
||||
var move = require('../lib/utils').move;
|
||||
var Syntax = require('esprima').Syntax;
|
||||
var append = require('jstransform/src/utils').append;
|
||||
var catchup = require('jstransform/src/utils').catchup;
|
||||
var move = require('jstransform/src/utils').move;
|
||||
var Syntax = require('esprima-fb').Syntax;
|
||||
|
||||
var knownTags = {
|
||||
a: true,
|
||||
|
||||
18
vendor/fbtransform/visitors.js
vendored
18
vendor/fbtransform/visitors.js
vendored
@@ -1,5 +1,5 @@
|
||||
/*global exports:true*/
|
||||
var classes = require('./transforms/classes');
|
||||
var es6Classes = require('jstransform/visitors/es6-class-visitors').visitorList;
|
||||
var react = require('./transforms/react');
|
||||
var reactDisplayName = require('./transforms/reactDisplayName');
|
||||
|
||||
@@ -7,21 +7,13 @@ var reactDisplayName = require('./transforms/reactDisplayName');
|
||||
* Map from transformName => orderedListOfVisitors.
|
||||
*/
|
||||
var transformVisitors = {
|
||||
'es6-classes': [
|
||||
classes.visitClassExpression,
|
||||
classes.visitClassDeclaration,
|
||||
classes.visitSuperCall,
|
||||
classes.visitPrivateProperty
|
||||
'es6-classes': es6Classes,
|
||||
'react': [
|
||||
react.visitReactTag,
|
||||
reactDisplayName.visitReactDisplayName
|
||||
]
|
||||
};
|
||||
|
||||
transformVisitors.react = transformVisitors[
|
||||
"es6-classes"
|
||||
].concat([
|
||||
react.visitReactTag,
|
||||
reactDisplayName.visitReactDisplayName
|
||||
]);
|
||||
|
||||
/**
|
||||
* Specifies the order in which each transform should run.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user