mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Merge pull request #3777 from zpao/deprecate-react-tools
Deprecate react-tools
This commit is contained in:
@@ -8,88 +8,31 @@
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
/*eslint-disable no-undef*/
|
||||
var visitors = require('./vendor/fbtransform/visitors');
|
||||
var transform = require('jstransform').transform;
|
||||
var typesSyntax = require('jstransform/visitors/type-syntax');
|
||||
var inlineSourceMap = require('./vendor/inline-source-map');
|
||||
|
||||
var jstransform = require('jstransform/simple');
|
||||
|
||||
function transformWithDetails(code, opts) {
|
||||
opts = opts || {};
|
||||
|
||||
// Copy out the values we need and make sure they are compatible with
|
||||
// jstransform options. Always set react:true.
|
||||
var options = {
|
||||
react: true,
|
||||
harmony: opts.harmony,
|
||||
stripTypes: opts.stripTypes,
|
||||
sourceMapInline: opts.sourceMap,
|
||||
sourceFilename: opts.sourceFilename,
|
||||
es6module: opts.es6module,
|
||||
nonStrictEs6module: opts.nonStrictEs6module,
|
||||
target: opts.target
|
||||
};
|
||||
|
||||
return jstransform.transform(code, options);
|
||||
}
|
||||
|
||||
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;
|
||||
return transformWithDetails(input, options).code;
|
||||
},
|
||||
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;
|
||||
}
|
||||
transformWithDetails: transformWithDetails
|
||||
};
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
opts = opts || {};
|
||||
var options = {};
|
||||
|
||||
options.harmony = opts.harmony;
|
||||
options.stripTypes = opts.stripTypes;
|
||||
options.sourceMap = opts.sourceMap;
|
||||
options.filename = opts.sourceFilename;
|
||||
|
||||
if (opts.es6module) {
|
||||
options.sourceType = 'module';
|
||||
}
|
||||
if (opts.nonStrictEs6module) {
|
||||
options.sourceType = 'nonStrictModule';
|
||||
}
|
||||
|
||||
// Instead of doing any fancy validation, only look for 'es3'. If we have
|
||||
// that, then use it. Otherwise use 'es5'.
|
||||
options.es3 = opts.target === 'es3';
|
||||
options.es5 = !options.es3;
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
+3
-4
@@ -14,9 +14,7 @@
|
||||
"files": [
|
||||
"main.js",
|
||||
"bin/jsx",
|
||||
"src/",
|
||||
"vendor/fbtransform/",
|
||||
"vendor/inline-source-map.js"
|
||||
"src/"
|
||||
],
|
||||
"main": "main.js",
|
||||
"bin": {
|
||||
@@ -28,7 +26,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"commoner": "^0.10.0",
|
||||
"jstransform": "^10.1.0"
|
||||
"esprima-fb": "^15001.1.0-dev-harmony-fb",
|
||||
"jstransform": "^11.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "^5.2.7",
|
||||
|
||||
Vendored
+26
-31
@@ -13,8 +13,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var ReactTools = require('../main');
|
||||
var inlineSourceMap = require('./inline-source-map');
|
||||
var jstransform = require('jstransform/simple');
|
||||
|
||||
var headEl;
|
||||
var dummyAnchor;
|
||||
@@ -36,6 +35,9 @@ var supportsAccessors = Object.prototype.hasOwnProperty('__defineGetter__');
|
||||
function transformReact(source, options) {
|
||||
options = options || {};
|
||||
|
||||
// Always enable the React transforms.
|
||||
options.react = true;
|
||||
|
||||
// Force the sourcemaps option manually. We don't want to use it if it will
|
||||
// break (see above note about supportsAccessors). We'll only override the
|
||||
// value here if sourceMap was specified and is truthy. This guarantees that
|
||||
@@ -45,7 +47,7 @@ function transformReact(source, options) {
|
||||
}
|
||||
|
||||
// Otherwise just pass all options straight through to react-tools.
|
||||
return ReactTools.transformWithDetails(source, options);
|
||||
return jstransform.transform(source, options);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,7 +121,7 @@ function createSourceCodeErrorMessage(code, e) {
|
||||
*/
|
||||
function transformCode(code, url, options) {
|
||||
try {
|
||||
var transformed = transformReact(code, options);
|
||||
return transformReact(code, options).code;
|
||||
} catch(e) {
|
||||
e.message += '\n at ';
|
||||
if (url) {
|
||||
@@ -136,32 +138,6 @@ function transformCode(code, url, options) {
|
||||
e.message += createSourceCodeErrorMessage(code, e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (!transformed.sourceMap) {
|
||||
return transformed.code;
|
||||
}
|
||||
|
||||
var source;
|
||||
if (url == null) {
|
||||
source = 'Inline JSX script';
|
||||
inlineScriptCount++;
|
||||
if (inlineScriptCount > 1) {
|
||||
source += ' (' + inlineScriptCount + ')';
|
||||
}
|
||||
} else if (dummyAnchor) {
|
||||
// Firefox has problems when the sourcemap source is a proper URL with a
|
||||
// protocol and hostname, so use the pathname. We could use just the
|
||||
// filename, but hopefully using the full path will prevent potential
|
||||
// issues where the same filename exists in multiple directories.
|
||||
dummyAnchor.href = url;
|
||||
source = dummyAnchor.pathname.substr(1);
|
||||
}
|
||||
|
||||
return (
|
||||
transformed.code +
|
||||
'\n' +
|
||||
inlineSourceMap(transformed.sourceMap, code, source)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -239,8 +215,27 @@ function loadScripts(scripts) {
|
||||
}
|
||||
|
||||
scripts.forEach(function(script, i) {
|
||||
// Determine the filename to use for the sourcemap.
|
||||
var sourceFilename;
|
||||
if (script.src == null) {
|
||||
sourceFilename = 'Inline JSX script';
|
||||
inlineScriptCount++;
|
||||
if (inlineScriptCount > 1) {
|
||||
sourceFilename += ' (' + inlineScriptCount + ')';
|
||||
}
|
||||
} else if (dummyAnchor) {
|
||||
// Firefox has problems when the sourcemap sourceFilename is a proper URL
|
||||
// with a protocol and hostname, so use the pathname. We could use just
|
||||
// the filename, but hopefully using the full path will prevent potential
|
||||
// issues where the same filename exists in multiple directories.
|
||||
dummyAnchor.href = script.src;
|
||||
sourceFilename = dummyAnchor.pathname.substr(1);
|
||||
}
|
||||
console.log(sourceFilename);
|
||||
|
||||
var options = {
|
||||
sourceMap: true
|
||||
sourceMapInline: true,
|
||||
sourceFilename: sourceFilename
|
||||
};
|
||||
if (/;harmony=true(;|$)/.test(script.type)) {
|
||||
options.harmony = true;
|
||||
|
||||
Vendored
-9
@@ -1,9 +0,0 @@
|
||||
---
|
||||
globals:
|
||||
describe: true
|
||||
expect: true
|
||||
it: true
|
||||
jest: true
|
||||
|
||||
rules:
|
||||
no-process-exit: 0
|
||||
Vendored
-94
@@ -1,94 +0,0 @@
|
||||
/*global process:false*/
|
||||
/*global module:true*/
|
||||
/*global exports:true*/
|
||||
"use strict";
|
||||
|
||||
var transform = require('jstransform').transform;
|
||||
var typesSyntax = require('jstransform/visitors/type-syntax');
|
||||
var visitors = require('./visitors');
|
||||
|
||||
/**
|
||||
* @typechecks
|
||||
* @param {string} source
|
||||
* @param {object?} options
|
||||
* @param {array?} excludes
|
||||
* @return {string}
|
||||
*/
|
||||
function transformAll(source, options, excludes) {
|
||||
excludes = excludes || [];
|
||||
|
||||
// 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
|
||||
source = transform(typesSyntax.visitorList, source, options).code;
|
||||
|
||||
// The typechecker transform must run in a second pass in order to operate on
|
||||
// the entire source code -- so exclude it from the first pass
|
||||
var visitorsList = visitors.getAllVisitors(excludes.concat('typechecker'));
|
||||
source = transform(visitorsList, source, options);
|
||||
if (excludes.indexOf('typechecks') == -1 && /@typechecks/.test(source.code)) {
|
||||
source = transform(
|
||||
visitors.transformVisitors.typechecker,
|
||||
source.code,
|
||||
options
|
||||
);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
function runCli(argv) {
|
||||
var options = {};
|
||||
for (var optName in argv) {
|
||||
if (optName === '_' || optName === '$0') {
|
||||
continue;
|
||||
}
|
||||
options[optName] = optimist.argv[optName];
|
||||
}
|
||||
|
||||
if (options.help) {
|
||||
optimist.showHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
var excludes = options.excludes;
|
||||
delete options.excludes;
|
||||
|
||||
var source = '';
|
||||
process.stdin.resume();
|
||||
process.stdin.setEncoding('utf8');
|
||||
process.stdin.on('data', function(chunk) {
|
||||
source += chunk;
|
||||
});
|
||||
process.stdin.on('end', function() {
|
||||
try {
|
||||
source = transformAll(source, options, excludes);
|
||||
} catch (e) {
|
||||
console.error(e.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
process.stdout.write(source.code);
|
||||
});
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
var optimist = require('optimist');
|
||||
|
||||
optimist = optimist
|
||||
.usage('Usage: $0 [options]')
|
||||
.default('exclude', [])
|
||||
.boolean('help').alias('h', 'help')
|
||||
.boolean('minify')
|
||||
.describe(
|
||||
'minify',
|
||||
'Best-effort minification of the output source (when possible)'
|
||||
)
|
||||
.describe(
|
||||
'exclude',
|
||||
'A list of transformNames to exclude'
|
||||
);
|
||||
|
||||
runCli(optimist.argv);
|
||||
} else {
|
||||
exports.transformAll = transformAll;
|
||||
}
|
||||
-142
@@ -1,142 +0,0 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @emails jeffmo@fb.com
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
require('mock-modules').autoMockOff();
|
||||
|
||||
describe('jsx', function() {
|
||||
var jsx = require('../jsx');
|
||||
var utils = require('jstransform/src/utils');
|
||||
var esprima = require('esprima-fb');
|
||||
|
||||
function runWithLiteral(text, isLast) {
|
||||
var source = '<div>' + text + '</div>';
|
||||
var ast = esprima.parse(source, { range: true });
|
||||
var state = utils.createState(source);
|
||||
var literal = ast.body[0].expression.children[0];
|
||||
state.g.position = literal.range[0];
|
||||
jsx.renderJSXLiteral(literal, isLast, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
function runWithAttribute(inlineAttribute, isLast) {
|
||||
var source = '<div ' + inlineAttribute + ' />';
|
||||
var ast = esprima.parse(source, { range: true });
|
||||
var state = utils.createState(source);
|
||||
var attribute = ast.body[0].expression.openingElement.attributes[0];
|
||||
state.g.position = attribute.value.range[0];
|
||||
jsx.renderJSXExpressionContainer(
|
||||
function() {},
|
||||
attribute.value,
|
||||
isLast,
|
||||
[],
|
||||
state
|
||||
);
|
||||
return state;
|
||||
}
|
||||
|
||||
it('should render simple literal', function() {
|
||||
var state = runWithLiteral('a', true);
|
||||
expect(state.g.buffer).toEqual('"a"');
|
||||
});
|
||||
|
||||
|
||||
it('should render simple literal with single space before', function() {
|
||||
var state = runWithLiteral(' a', true);
|
||||
expect(state.g.buffer).toEqual('" a"');
|
||||
});
|
||||
|
||||
it('should render simple literal with single space before' +
|
||||
' from multiple spaces', function() {
|
||||
var state = runWithLiteral(' \t a', true);
|
||||
expect(state.g.buffer).toEqual('" a"');
|
||||
});
|
||||
|
||||
it('should render simple literal with single space after', function() {
|
||||
var state = runWithLiteral('a ', true);
|
||||
expect(state.g.buffer).toEqual('"a "');
|
||||
});
|
||||
|
||||
it('should render simple literal with single space after' +
|
||||
' from multiple spaces', function() {
|
||||
var state = runWithLiteral('a \t \t ', true);
|
||||
expect(state.g.buffer).toEqual('"a "');
|
||||
});
|
||||
|
||||
it('should render multiline literal as last', function() {
|
||||
var state = runWithLiteral(
|
||||
' sdfsdfsdf\n' +
|
||||
' sdlkfjsdfljs\n' +
|
||||
' ',
|
||||
true);
|
||||
|
||||
expect(state.g.buffer).toEqual(
|
||||
'" sdfsdfsdf" + \' \' +\n' +
|
||||
' "sdlkfjsdfljs"\n' +
|
||||
' ');
|
||||
});
|
||||
|
||||
it('should render multiline literal as not last', function() {
|
||||
var state = runWithLiteral(
|
||||
' sdfsdfsdf\n' +
|
||||
' sdlkfjsdfljs\n' +
|
||||
' ',
|
||||
false);
|
||||
|
||||
expect(state.g.buffer).toEqual(
|
||||
'" sdfsdfsdf" + \' \' +\n' +
|
||||
' "sdlkfjsdfljs", \n' +
|
||||
' ');
|
||||
});
|
||||
|
||||
it('should render attribute expressions', function() {
|
||||
var state = runWithAttribute('attr={"foo"}', true);
|
||||
expect(state.g.buffer).toEqual('"foo"');
|
||||
});
|
||||
|
||||
it('should render attribute expressions as not last', function() {
|
||||
var state = runWithAttribute('attr={"foo"}', false);
|
||||
expect(state.g.buffer).toEqual('"foo", ');
|
||||
});
|
||||
|
||||
it('should render attribute expressions with spaces', function() {
|
||||
var state = runWithAttribute('attr={ "foo"\n }', true);
|
||||
expect(state.g.buffer).toEqual(' "foo"\n ');
|
||||
});
|
||||
|
||||
it('should render attribute expressions with commas before trailing ' +
|
||||
'whitespace', function() {
|
||||
var state = runWithAttribute('attr={\n"foo"\n }', false);
|
||||
expect(state.g.buffer).toEqual('\n"foo", \n ');
|
||||
});
|
||||
|
||||
it('should render empty child expressions with comments', function() {
|
||||
var source = '<div>{/*comment*/}</div>';
|
||||
var ast = esprima.parse(source, {range: true});
|
||||
var child = ast.body[0].expression.children[0];
|
||||
var state = utils.createState(source, child);
|
||||
state.g.position = child.range[0];
|
||||
jsx.renderJSXExpressionContainer(function() {}, child, true, [], state);
|
||||
expect(state.g.buffer).toBe('/*comment*/');
|
||||
});
|
||||
|
||||
it('should not render commas after empty child expressions even if they\'re' +
|
||||
'not last', function() {
|
||||
var source = '<div>{/*comment*/}</div>';
|
||||
var ast = esprima.parse(source, {range: true});
|
||||
var child = ast.body[0].expression.children[0];
|
||||
var state = utils.createState(source, child);
|
||||
state.g.position = child.range[0];
|
||||
jsx.renderJSXExpressionContainer(function() {}, child, false, [], state);
|
||||
expect(state.g.buffer).toBe('/*comment*/');
|
||||
});
|
||||
});
|
||||
@@ -1,174 +0,0 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @emails react-core
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
require('mock-modules').autoMockOff();
|
||||
|
||||
var transformAll = require('../../syntax.js').transformAll;
|
||||
|
||||
function transform(source) {
|
||||
return transformAll(source, {}, ['sourcemeta']);
|
||||
}
|
||||
|
||||
describe('react displayName jsx', function() {
|
||||
|
||||
it('should only inject displayName if missing', function() {
|
||||
var code = [
|
||||
'"use strict";',
|
||||
'var Whateva = React.createClass({',
|
||||
' displayName: "Whateva",',
|
||||
' render: function() {',
|
||||
' return null;',
|
||||
' }',
|
||||
'});'
|
||||
].join('\n');
|
||||
|
||||
var result = [
|
||||
'"use strict";',
|
||||
'var Whateva = React.createClass({',
|
||||
' displayName: "Whateva",',
|
||||
' render: function() {',
|
||||
' return null;',
|
||||
' }',
|
||||
'});'
|
||||
].join('\n');
|
||||
|
||||
expect(transform(code).code).toEqual(result);
|
||||
});
|
||||
|
||||
it('should inject displayName in simple assignment', () => {
|
||||
var code = [
|
||||
'var Component = React.createClass({',
|
||||
' render: function() {',
|
||||
' return null;',
|
||||
' }',
|
||||
'});'
|
||||
].join('\n');
|
||||
|
||||
var result = [
|
||||
'var Component = React.createClass({displayName: "Component",',
|
||||
' render: function() {',
|
||||
' return null;',
|
||||
' }',
|
||||
'});'
|
||||
].join('\n');
|
||||
|
||||
expect(transform(code).code).toEqual(result);
|
||||
});
|
||||
|
||||
it('should inject displayName in simple assignment without var', () => {
|
||||
var code = [
|
||||
'var Component;',
|
||||
'Component = React.createClass({',
|
||||
' render: function() {',
|
||||
' return null;',
|
||||
' }',
|
||||
'});'
|
||||
].join('\n');
|
||||
|
||||
var result = [
|
||||
'var Component;',
|
||||
'Component = React.createClass({displayName: "Component",',
|
||||
' render: function() {',
|
||||
' return null;',
|
||||
' }',
|
||||
'});'
|
||||
].join('\n');
|
||||
|
||||
expect(transform(code).code).toEqual(result);
|
||||
});
|
||||
|
||||
it('should inject displayName in property assignment', () => {
|
||||
var code = [
|
||||
'ns.Component = React.createClass({',
|
||||
' render: function() {',
|
||||
' return null;',
|
||||
' }',
|
||||
'});'
|
||||
].join('\n');
|
||||
|
||||
var result = [
|
||||
'ns.Component = React.createClass({displayName: "ns.Component",',
|
||||
' render: function() {',
|
||||
' return null;',
|
||||
' }',
|
||||
'});'
|
||||
].join('\n');
|
||||
|
||||
expect(transform(code).code).toEqual(result);
|
||||
});
|
||||
|
||||
it('should inject displayName in chained property assignment', () => {
|
||||
var code = [
|
||||
'ns.ns1.Component = React.createClass({',
|
||||
' render: function() {',
|
||||
' return null;',
|
||||
' }',
|
||||
'});'
|
||||
].join('\n');
|
||||
|
||||
var result = [
|
||||
'ns.ns1.Component = React.createClass({displayName: "ns.ns1.Component",',
|
||||
' render: function() {',
|
||||
' return null;',
|
||||
' }',
|
||||
'});'
|
||||
].join('\n');
|
||||
|
||||
expect(transform(code).code).toEqual(result);
|
||||
});
|
||||
|
||||
|
||||
it('should inject displayName in exports property assignment', () => {
|
||||
var code = [
|
||||
'exports.Component = React.createClass({',
|
||||
' render: function() {',
|
||||
' return null;',
|
||||
' }',
|
||||
'});'
|
||||
].join('\n');
|
||||
|
||||
var result = [
|
||||
'exports.Component = React.createClass({displayName: "Component",',
|
||||
' render: function() {',
|
||||
' return null;',
|
||||
' }',
|
||||
'});'
|
||||
].join('\n');
|
||||
|
||||
expect(transform(code).code).toEqual(result);
|
||||
});
|
||||
|
||||
it('should inject displayName in object declaration', () => {
|
||||
var code = [
|
||||
'exports = {',
|
||||
' Component: React.createClass({',
|
||||
' render: function() {',
|
||||
' return null;',
|
||||
' }',
|
||||
' })',
|
||||
'};'
|
||||
].join('\n');
|
||||
|
||||
var result = [
|
||||
'exports = {',
|
||||
' Component: React.createClass({displayName: "Component",',
|
||||
' render: function() {',
|
||||
' return null;',
|
||||
' }',
|
||||
' })',
|
||||
'};'
|
||||
].join('\n');
|
||||
|
||||
expect(transform(code).code).toEqual(result);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,396 +0,0 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @emails react-core
|
||||
*/
|
||||
|
||||
/*jshint evil:true, unused:false*/
|
||||
|
||||
'use strict';
|
||||
|
||||
require('mock-modules').autoMockOff();
|
||||
|
||||
describe('react jsx', function() {
|
||||
var transformAll = require('../../syntax.js').transformAll;
|
||||
|
||||
var transform = function(code, options, excludes) {
|
||||
return transformAll(
|
||||
code,
|
||||
options,
|
||||
(excludes || []).concat(['sourcemeta'])
|
||||
);
|
||||
};
|
||||
|
||||
// These are placeholder variables in scope that we can use to assert that a
|
||||
// specific variable reference was passed, rather than an object clone of it.
|
||||
var x = 123456;
|
||||
var y = 789012;
|
||||
var z = 345678;
|
||||
|
||||
var expectObjectAssign = function(code) {
|
||||
/*eslint-disable no-unused-vars, no-eval*/
|
||||
var Component = jest.genMockFunction();
|
||||
var Child = jest.genMockFunction();
|
||||
var objectAssignMock = jest.genMockFunction();
|
||||
React.__spread = objectAssignMock;
|
||||
eval(transform(code).code);
|
||||
return expect(objectAssignMock);
|
||||
/*eslint-enable*/
|
||||
};
|
||||
|
||||
var React = {
|
||||
createElement: jest.genMockFunction()
|
||||
};
|
||||
|
||||
it('should convert simple tags', function() {
|
||||
var code = 'var x = <div></div>;';
|
||||
var result = 'var x = React.createElement("div", null);';
|
||||
|
||||
expect(transform(code).code).toEqual(result);
|
||||
});
|
||||
|
||||
it('should convert simple text', function() {
|
||||
var code = 'var x = <div>text</div>;';
|
||||
var result = 'var x = React.createElement("div", null, "text");';
|
||||
|
||||
expect(transform(code).code).toEqual(result);
|
||||
});
|
||||
|
||||
it('should have correct comma in nested children', function() {
|
||||
var code = [
|
||||
'var x = <div>',
|
||||
' <div><br /></div>',
|
||||
' <Component>{foo}<br />{bar}</Component>',
|
||||
' <br />',
|
||||
'</div>;'
|
||||
].join('\n');
|
||||
var result = [
|
||||
'var x = React.createElement("div", null, ',
|
||||
' React.createElement("div", null, ' +
|
||||
'React.createElement("br", null)), ',
|
||||
' React.createElement(Component, null, foo, ' +
|
||||
'React.createElement("br", null), bar), ',
|
||||
' React.createElement("br", null)',
|
||||
');'
|
||||
].join('\n');
|
||||
|
||||
expect(transform(code).code).toEqual(result);
|
||||
});
|
||||
|
||||
it('should avoid wrapping in extra parens if not needed', function() {
|
||||
// Try with a single composite child, wrapped in a div.
|
||||
var code = [
|
||||
'var x = <div>',
|
||||
' <Component />',
|
||||
'</div>;'
|
||||
].join('\n');
|
||||
var result = [
|
||||
'var x = React.createElement("div", null, ',
|
||||
' React.createElement(Component, null)',
|
||||
');'
|
||||
].join('\n');
|
||||
|
||||
expect(transform(code).code).toEqual(result);
|
||||
|
||||
// Try with a single interpolated child, wrapped in a div.
|
||||
code = [
|
||||
'var x = <div>',
|
||||
' {this.props.children}',
|
||||
'</div>;'
|
||||
].join('\n');
|
||||
result = [
|
||||
'var x = React.createElement("div", null, ',
|
||||
' this.props.children',
|
||||
');'
|
||||
].join('\n');
|
||||
expect(transform(code).code).toEqual(result);
|
||||
|
||||
// Try with a single interpolated child, wrapped in a composite.
|
||||
code = [
|
||||
'var x = <Composite>',
|
||||
' {this.props.children}',
|
||||
'</Composite>;'
|
||||
].join('\n');
|
||||
result = [
|
||||
'var x = React.createElement(Composite, null, ',
|
||||
' this.props.children',
|
||||
');'
|
||||
].join('\n');
|
||||
expect(transform(code).code).toEqual(result);
|
||||
|
||||
// Try with a single composite child, wrapped in a composite.
|
||||
code = [
|
||||
'var x = <Composite>',
|
||||
' <Composite2 />',
|
||||
'</Composite>;'
|
||||
].join('\n');
|
||||
result = [
|
||||
'var x = React.createElement(Composite, null, ',
|
||||
' React.createElement(Composite2, null)',
|
||||
');'
|
||||
].join('\n');
|
||||
expect(transform(code).code).toEqual(result);
|
||||
});
|
||||
|
||||
it('should insert commas after expressions before whitespace', function() {
|
||||
var code = [
|
||||
'var x =',
|
||||
' <div',
|
||||
' attr1={',
|
||||
' "foo" + "bar"',
|
||||
' }',
|
||||
' attr2={',
|
||||
' "foo" + "bar" +',
|
||||
' ',
|
||||
' "baz" + "bug"',
|
||||
' }',
|
||||
' attr3={',
|
||||
' "foo" + "bar" +',
|
||||
' "baz" + "bug"',
|
||||
' // Extra line here.',
|
||||
' }',
|
||||
' attr4="baz">',
|
||||
' </div>;'
|
||||
].join('\n');
|
||||
var result = [
|
||||
'var x =',
|
||||
' React.createElement("div", {',
|
||||
' attr1: ',
|
||||
' "foo" + "bar", ',
|
||||
' ',
|
||||
' attr2: ',
|
||||
' "foo" + "bar" +',
|
||||
' ',
|
||||
' "baz" + "bug", ',
|
||||
' ',
|
||||
' attr3: ',
|
||||
' "foo" + "bar" +',
|
||||
' "baz" + "bug", ',
|
||||
' // Extra line here.',
|
||||
' ',
|
||||
' attr4: "baz"}',
|
||||
' );'
|
||||
].join('\n');
|
||||
|
||||
expect(transform(code).code).toEqual(result);
|
||||
});
|
||||
|
||||
it('should properly handle comments adjacent to children', function() {
|
||||
var code = [
|
||||
'var x = (',
|
||||
' <div>',
|
||||
' {/* A comment at the beginning */}',
|
||||
' {/* A second comment at the beginning */}',
|
||||
' <span>',
|
||||
' {/* A nested comment */}',
|
||||
' </span>',
|
||||
' {/* A sandwiched comment */}',
|
||||
' <br />',
|
||||
' {/* A comment at the end */}',
|
||||
' {/* A second comment at the end */}',
|
||||
' </div>',
|
||||
');'
|
||||
].join('\n');
|
||||
var result = [
|
||||
'var x = (',
|
||||
' React.createElement("div", null, ',
|
||||
' /* A comment at the beginning */',
|
||||
' /* A second comment at the beginning */',
|
||||
' React.createElement("span", null',
|
||||
' /* A nested comment */',
|
||||
' ), ',
|
||||
' /* A sandwiched comment */',
|
||||
' React.createElement("br", null)',
|
||||
' /* A comment at the end */',
|
||||
' /* A second comment at the end */',
|
||||
' )',
|
||||
');'
|
||||
].join('\n');
|
||||
|
||||
expect(transform(code).code).toBe(result);
|
||||
});
|
||||
|
||||
it('should properly handle comments between props', function() {
|
||||
var code = [
|
||||
'var x = (',
|
||||
' <div',
|
||||
' /* a multi-line',
|
||||
' comment */',
|
||||
' attr1="foo">',
|
||||
' <span // a double-slash comment',
|
||||
' attr2="bar"',
|
||||
' />',
|
||||
' </div>',
|
||||
');'
|
||||
].join('\n');
|
||||
var result = [
|
||||
'var x = (',
|
||||
' React.createElement("div", {',
|
||||
' /* a multi-line',
|
||||
' comment */',
|
||||
' attr1: "foo"}, ',
|
||||
' React.createElement("span", {// a double-slash comment',
|
||||
' attr2: "bar"}',
|
||||
' )',
|
||||
' )',
|
||||
');'
|
||||
].join('\n');
|
||||
|
||||
expect(transform(code).code).toBe(result);
|
||||
});
|
||||
|
||||
it('should not strip tags with a single child of ', function() {
|
||||
var code = [
|
||||
'<div> </div>;'
|
||||
].join('\n');
|
||||
var result = [
|
||||
'React.createElement("div", null, "\u00A0");'
|
||||
].join('\n');
|
||||
|
||||
expect(transform(code).code).toBe(result);
|
||||
});
|
||||
|
||||
it('should not strip even coupled with other whitespace', function() {
|
||||
var code = [
|
||||
'<div> </div>;'
|
||||
].join('\n');
|
||||
var result = [
|
||||
'React.createElement("div", null, "\u00A0 ");'
|
||||
].join('\n');
|
||||
|
||||
expect(transform(code).code).toBe(result);
|
||||
});
|
||||
|
||||
it('should handle hasOwnProperty correctly', function() {
|
||||
var code = '<hasOwnProperty>testing</hasOwnProperty>;';
|
||||
var result = 'React.createElement("hasOwnProperty", null, "testing");';
|
||||
expect(transform(code).code).toBe(result);
|
||||
});
|
||||
|
||||
it('should allow constructor as prop', function() {
|
||||
var code = '<Component constructor="foo" />;';
|
||||
var result = 'React.createElement(Component, {constructor: "foo"});';
|
||||
|
||||
expect(transform(code).code).toBe(result);
|
||||
});
|
||||
|
||||
it('should allow JS namespacing', function() {
|
||||
var code = '<Namespace.Component />;';
|
||||
var result = 'React.createElement(Namespace.Component, null);';
|
||||
|
||||
expect(transform(code).code).toBe(result);
|
||||
});
|
||||
|
||||
it('should allow deeper JS namespacing', function() {
|
||||
var code = '<Namespace.DeepNamespace.Component />;';
|
||||
var result =
|
||||
'React.createElement(Namespace.DeepNamespace.Component, null);';
|
||||
|
||||
expect(transform(code).code).toBe(result);
|
||||
});
|
||||
|
||||
it('should disallow XML namespacing', function() {
|
||||
var code = '<Namespace:Component />;';
|
||||
|
||||
expect(() => transform(code)).toThrow();
|
||||
});
|
||||
|
||||
it('wraps props in React.__spread for spread attributes', function() {
|
||||
var code =
|
||||
'<Component { ... x } y\n' +
|
||||
'={2 } z />';
|
||||
var result =
|
||||
'React.createElement(Component, React.__spread({}, x , {y: \n' +
|
||||
'2, z: true}))';
|
||||
|
||||
expect(transform(code).code).toBe(result);
|
||||
});
|
||||
|
||||
it('adds appropriate newlines when using spread attribute', function() {
|
||||
var code =
|
||||
'<Component\n' +
|
||||
' {...this.props}\n' +
|
||||
' sound="moo" />';
|
||||
var result =
|
||||
'React.createElement(Component, React.__spread({}, \n' +
|
||||
' this.props, \n' +
|
||||
' {sound: "moo"}))';
|
||||
|
||||
expect(transform(code).code).toBe(result);
|
||||
});
|
||||
|
||||
it('handles overparenthesized JS', function() {
|
||||
var code =
|
||||
'<foo a={(b)} c={(d)}>Foo {(e+f //A line comment\n' +
|
||||
'/* A multiline comment */)\n' +
|
||||
'} bar\n' +
|
||||
'</foo>';
|
||||
var result = 'React.createElement("foo", {a: (b), c: (d)}, "Foo ", (e+f //A line comment\n' +
|
||||
'/* A multiline comment */), \n' +
|
||||
'" bar"\n' +
|
||||
')';
|
||||
expect(transform(code).code).toBe(result);
|
||||
});
|
||||
|
||||
it('should transform known hyphenated tags', function() {
|
||||
var code = '<font-face />;';
|
||||
var result = 'React.createElement("font-face", null);';
|
||||
|
||||
expect(transform(code).code).toBe(result);
|
||||
});
|
||||
|
||||
it('does not call React.__spread when there are no spreads', function() {
|
||||
expectObjectAssign(
|
||||
'<Component x={y} />'
|
||||
).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('should not throw for unknown hyphenated tags', function() {
|
||||
var code = '<x-component />;';
|
||||
expect(function() {
|
||||
transform(code);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('calls assign with a new target object for spreads', function() {
|
||||
expectObjectAssign(
|
||||
'<Component {...x} />'
|
||||
).toBeCalledWith({}, x);
|
||||
});
|
||||
|
||||
it('calls assign with an empty object when the spread is first', function() {
|
||||
expectObjectAssign(
|
||||
'<Component { ...x } y={2} />'
|
||||
).toBeCalledWith({}, x, {y: 2});
|
||||
});
|
||||
|
||||
it('coalesces consecutive properties into a single object', function() {
|
||||
expectObjectAssign(
|
||||
'<Component { ... x } y={2} z />'
|
||||
).toBeCalledWith({}, x, {y: 2, z: true});
|
||||
});
|
||||
|
||||
it('avoids an unnecessary empty object when spread is not first', function() {
|
||||
expectObjectAssign(
|
||||
'<Component x={1} {...y} />'
|
||||
).toBeCalledWith({x: 1}, y);
|
||||
});
|
||||
|
||||
it('passes the same value multiple times to React.__spread', function() {
|
||||
expectObjectAssign(
|
||||
'<Component x={1} y="2" {...z} {...z}><Child /></Component>'
|
||||
).toBeCalledWith({x: 1, y: '2'}, z, z);
|
||||
});
|
||||
|
||||
it('evaluates sequences before passing them to React.__spread', function() {
|
||||
expectObjectAssign(
|
||||
'<Component x="1" {...(z = { y: 2 }, z)} z={3}>Text</Component>'
|
||||
).toBeCalledWith({x: '1'}, {y: 2}, {z: 3});
|
||||
});
|
||||
|
||||
});
|
||||
Vendored
-138
@@ -1,138 +0,0 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
/*global exports:true*/
|
||||
'use strict';
|
||||
var Syntax = require('jstransform').Syntax;
|
||||
var utils = require('jstransform/src/utils');
|
||||
|
||||
function commaAfterLastParen(value) {
|
||||
var state = 'normal';
|
||||
var commaPos = 0;
|
||||
for (var i = 0; i < value.length; ++i) {
|
||||
if (state === 'normal') {
|
||||
if (value.substr(i, 2) === '//') {
|
||||
state = 'singleline';
|
||||
i += 1;
|
||||
} else if (value.substr(i, 2) === '/*') {
|
||||
state = 'multiline';
|
||||
i += 1;
|
||||
} else if (value.charAt(i).trim() !== '') {
|
||||
commaPos = i + 1;
|
||||
}
|
||||
} else if (state === 'singleline' && value.charAt(i) === '\n') {
|
||||
state = 'normal';
|
||||
} else if (state === 'multiline' &&
|
||||
value.charAt(i) === '*' &&
|
||||
i + 1 < value.length &&
|
||||
value.charAt(i + 1) === '/') {
|
||||
i += 1;
|
||||
state = 'normal';
|
||||
}
|
||||
}
|
||||
return value.substring(0, commaPos) + ', ' + trimLeft(value.substring(commaPos));
|
||||
}
|
||||
|
||||
function renderJSXLiteral(object, isLast, state, start, end) {
|
||||
var lines = object.value.split(/\r\n|\n|\r/);
|
||||
|
||||
if (start) {
|
||||
utils.append(start, state);
|
||||
}
|
||||
|
||||
var lastNonEmptyLine = 0;
|
||||
|
||||
lines.forEach(function(line, index) {
|
||||
if (line.match(/[^ \t]/)) {
|
||||
lastNonEmptyLine = index;
|
||||
}
|
||||
});
|
||||
|
||||
lines.forEach(function(line, index) {
|
||||
var isFirstLine = index === 0;
|
||||
var isLastLine = index === lines.length - 1;
|
||||
var isLastNonEmptyLine = index === lastNonEmptyLine;
|
||||
|
||||
// replace rendered whitespace tabs with spaces
|
||||
var trimmedLine = line.replace(/\t/g, ' ');
|
||||
|
||||
// trim whitespace touching a newline
|
||||
if (!isFirstLine) {
|
||||
trimmedLine = trimmedLine.replace(/^[ ]+/, '');
|
||||
}
|
||||
if (!isLastLine) {
|
||||
trimmedLine = trimmedLine.replace(/[ ]+$/, '');
|
||||
}
|
||||
|
||||
if (!isFirstLine) {
|
||||
utils.append(line.match(/^[ \t]*/)[0], state);
|
||||
}
|
||||
|
||||
if (trimmedLine || isLastNonEmptyLine) {
|
||||
utils.append(
|
||||
JSON.stringify(trimmedLine) +
|
||||
(!isLastNonEmptyLine ? ' + \' \' +' : ''),
|
||||
state);
|
||||
|
||||
if (isLastNonEmptyLine) {
|
||||
if (end) {
|
||||
utils.append(end, state);
|
||||
}
|
||||
if (!isLast) {
|
||||
utils.append(', ', state);
|
||||
}
|
||||
}
|
||||
|
||||
// only restore tail whitespace if line had literals
|
||||
if (trimmedLine && !isLastLine) {
|
||||
utils.append(line.match(/[ \t]*$/)[0], state);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isLastLine) {
|
||||
utils.append('\n', state);
|
||||
}
|
||||
});
|
||||
|
||||
utils.move(object.range[1], state);
|
||||
}
|
||||
|
||||
function renderJSXExpressionContainer(traverse, object, isLast, path, state) {
|
||||
// Plus 1 to skip `{`.
|
||||
utils.move(object.range[0] + 1, state);
|
||||
utils.catchup(object.expression.range[0], state);
|
||||
traverse(object.expression, path, state);
|
||||
|
||||
if (!isLast && object.expression.type !== Syntax.JSXEmptyExpression) {
|
||||
// If we need to append a comma, make sure to do so after the expression.
|
||||
utils.catchup(object.expression.range[1], state, trimLeft);
|
||||
utils.catchup(object.range[1] - 1, state, commaAfterLastParen);
|
||||
} else {
|
||||
// Minus 1 to skip `}`.
|
||||
utils.catchup(object.range[1] - 1, state, trimLeft);
|
||||
}
|
||||
utils.move(object.range[1], state);
|
||||
return false;
|
||||
}
|
||||
|
||||
function quoteAttrName(attr) {
|
||||
// Quote invalid JS identifiers.
|
||||
if (!/^[a-z_$][a-z\d_$]*$/i.test(attr)) {
|
||||
return '"' + attr + '"';
|
||||
}
|
||||
return attr;
|
||||
}
|
||||
|
||||
function trimLeft(value) {
|
||||
return value.replace(/^[ ]+/, '');
|
||||
}
|
||||
|
||||
exports.renderJSXExpressionContainer = renderJSXExpressionContainer;
|
||||
exports.renderJSXLiteral = renderJSXLiteral;
|
||||
exports.quoteAttrName = quoteAttrName;
|
||||
exports.trimLeft = trimLeft;
|
||||
-241
@@ -1,241 +0,0 @@
|
||||
/**
|
||||
* 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';
|
||||
|
||||
/*global exports:true*/
|
||||
|
||||
var Syntax = require('jstransform').Syntax;
|
||||
var utils = require('jstransform/src/utils');
|
||||
|
||||
var renderJSXExpressionContainer = require('./jsx').renderJSXExpressionContainer;
|
||||
var renderJSXLiteral = require('./jsx').renderJSXLiteral;
|
||||
var quoteAttrName = require('./jsx').quoteAttrName;
|
||||
|
||||
var trimLeft = require('./jsx').trimLeft;
|
||||
|
||||
/**
|
||||
* Customized desugar processor for React JSX. Currently:
|
||||
*
|
||||
* <X> </X> => React.createElement(X, null)
|
||||
* <X prop="1" /> => React.createElement(X, {prop: '1'}, null)
|
||||
* <X prop="2"><Y /></X> => React.createElement(X, {prop:'2'},
|
||||
* React.createElement(Y, null)
|
||||
* )
|
||||
* <div /> => React.createElement("div", null)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Removes all non-whitespace/parenthesis characters
|
||||
*/
|
||||
var reNonWhiteParen = /([^\s\(\)])/g;
|
||||
function stripNonWhiteParen(value) {
|
||||
return value.replace(reNonWhiteParen, '');
|
||||
}
|
||||
|
||||
var tagConvention = /^[a-z]|\-/;
|
||||
function isTagName(name) {
|
||||
return tagConvention.test(name);
|
||||
}
|
||||
|
||||
function visitReactTag(traverse, object, path, state) {
|
||||
var openingElement = object.openingElement;
|
||||
var nameObject = openingElement.name;
|
||||
var attributesObject = openingElement.attributes;
|
||||
|
||||
utils.catchup(openingElement.range[0], state, trimLeft);
|
||||
|
||||
if (nameObject.type === Syntax.JSXNamespacedName && nameObject.namespace) {
|
||||
throw new Error('Namespace tags are not supported. ReactJSX is not XML.');
|
||||
}
|
||||
|
||||
// We assume that the React runtime is already in scope
|
||||
utils.append('React.createElement(', state);
|
||||
|
||||
if (nameObject.type === Syntax.JSXIdentifier && isTagName(nameObject.name)) {
|
||||
utils.append('"' + nameObject.name + '"', state);
|
||||
utils.move(nameObject.range[1], state);
|
||||
} else {
|
||||
// Use utils.catchup in this case so we can easily handle
|
||||
// JSXMemberExpressions which look like Foo.Bar.Baz. This also handles
|
||||
// JSXIdentifiers that aren't fallback tags.
|
||||
utils.move(nameObject.range[0], state);
|
||||
utils.catchup(nameObject.range[1], state);
|
||||
}
|
||||
|
||||
utils.append(', ', state);
|
||||
|
||||
var hasAttributes = attributesObject.length;
|
||||
|
||||
var hasAtLeastOneSpreadProperty = attributesObject.some(function(attr) {
|
||||
return attr.type === Syntax.JSXSpreadAttribute;
|
||||
});
|
||||
|
||||
// if we don't have any attributes, pass in null
|
||||
if (hasAtLeastOneSpreadProperty) {
|
||||
utils.append('React.__spread({', state);
|
||||
} else if (hasAttributes) {
|
||||
utils.append('{', state);
|
||||
} else {
|
||||
utils.append('null', state);
|
||||
}
|
||||
|
||||
// keep track of if the previous attribute was a spread attribute
|
||||
var previousWasSpread = false;
|
||||
|
||||
// write attributes
|
||||
attributesObject.forEach(function(attr, index) {
|
||||
var isLast = index === attributesObject.length - 1;
|
||||
|
||||
if (attr.type === Syntax.JSXSpreadAttribute) {
|
||||
// Close the previous object or initial object
|
||||
if (!previousWasSpread) {
|
||||
utils.append('}, ', state);
|
||||
}
|
||||
|
||||
// Move to the expression start, ignoring everything except parenthesis
|
||||
// and whitespace.
|
||||
utils.catchup(attr.range[0], state, stripNonWhiteParen);
|
||||
// Plus 1 to skip `{`.
|
||||
utils.move(attr.range[0] + 1, state);
|
||||
utils.catchup(attr.argument.range[0], state, stripNonWhiteParen);
|
||||
|
||||
traverse(attr.argument, path, state);
|
||||
|
||||
utils.catchup(attr.argument.range[1], state);
|
||||
|
||||
// Move to the end, ignoring parenthesis and the closing `}`
|
||||
utils.catchup(attr.range[1] - 1, state, stripNonWhiteParen);
|
||||
|
||||
if (!isLast) {
|
||||
utils.append(', ', state);
|
||||
}
|
||||
|
||||
utils.move(attr.range[1], state);
|
||||
|
||||
previousWasSpread = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If the next attribute is a spread, we're effective last in this object
|
||||
if (!isLast) {
|
||||
isLast = attributesObject[index + 1].type === Syntax.JSXSpreadAttribute;
|
||||
}
|
||||
|
||||
if (attr.name.namespace) {
|
||||
throw new Error(
|
||||
'Namespace attributes are not supported. ReactJSX is not XML.');
|
||||
}
|
||||
var name = attr.name.name;
|
||||
|
||||
utils.catchup(attr.range[0], state, trimLeft);
|
||||
|
||||
if (previousWasSpread) {
|
||||
utils.append('{', state);
|
||||
}
|
||||
|
||||
utils.append(quoteAttrName(name), state);
|
||||
utils.append(': ', state);
|
||||
|
||||
if (!attr.value) {
|
||||
state.g.buffer += 'true';
|
||||
state.g.position = attr.name.range[1];
|
||||
if (!isLast) {
|
||||
utils.append(', ', state);
|
||||
}
|
||||
} else {
|
||||
utils.move(attr.name.range[1], state);
|
||||
// Use catchupNewlines to skip over the '=' in the attribute
|
||||
utils.catchupNewlines(attr.value.range[0], state);
|
||||
if (attr.value.type === Syntax.Literal) {
|
||||
renderJSXLiteral(attr.value, isLast, state);
|
||||
} else {
|
||||
renderJSXExpressionContainer(traverse, attr.value, isLast, path, state);
|
||||
}
|
||||
}
|
||||
|
||||
utils.catchup(attr.range[1], state, trimLeft);
|
||||
|
||||
previousWasSpread = false;
|
||||
});
|
||||
|
||||
if (!openingElement.selfClosing) {
|
||||
utils.catchup(openingElement.range[1] - 1, state, trimLeft);
|
||||
utils.move(openingElement.range[1], state);
|
||||
}
|
||||
|
||||
if (hasAttributes && !previousWasSpread) {
|
||||
utils.append('}', state);
|
||||
}
|
||||
|
||||
if (hasAtLeastOneSpreadProperty) {
|
||||
utils.append(')', state);
|
||||
}
|
||||
|
||||
// filter out whitespace
|
||||
var childrenToRender = object.children.filter(function(child) {
|
||||
return !(child.type === Syntax.Literal
|
||||
&& typeof child.value === 'string'
|
||||
&& child.value.match(/^[ \t]*[\r\n][ \t\r\n]*$/));
|
||||
});
|
||||
if (childrenToRender.length > 0) {
|
||||
var lastRenderableIndex;
|
||||
|
||||
childrenToRender.forEach(function(child, index) {
|
||||
if (child.type !== Syntax.JSXExpressionContainer ||
|
||||
child.expression.type !== Syntax.JSXEmptyExpression) {
|
||||
lastRenderableIndex = index;
|
||||
}
|
||||
});
|
||||
|
||||
if (lastRenderableIndex !== undefined) {
|
||||
utils.append(', ', state);
|
||||
}
|
||||
|
||||
childrenToRender.forEach(function(child, index) {
|
||||
utils.catchup(child.range[0], state, trimLeft);
|
||||
|
||||
var isLast = index >= lastRenderableIndex;
|
||||
|
||||
if (child.type === Syntax.Literal) {
|
||||
renderJSXLiteral(child, isLast, state);
|
||||
} else if (child.type === Syntax.JSXExpressionContainer) {
|
||||
renderJSXExpressionContainer(traverse, child, isLast, path, state);
|
||||
} else {
|
||||
traverse(child, path, state);
|
||||
if (!isLast) {
|
||||
utils.append(', ', state);
|
||||
}
|
||||
}
|
||||
|
||||
utils.catchup(child.range[1], state, trimLeft);
|
||||
});
|
||||
}
|
||||
|
||||
if (openingElement.selfClosing) {
|
||||
// everything up to />
|
||||
utils.catchup(openingElement.range[1] - 2, state, trimLeft);
|
||||
utils.move(openingElement.range[1], state);
|
||||
} else {
|
||||
// everything up to </ sdflksjfd>
|
||||
utils.catchup(object.closingElement.range[0], state, trimLeft);
|
||||
utils.move(object.closingElement.range[1], state);
|
||||
}
|
||||
|
||||
utils.append(')', state);
|
||||
return false;
|
||||
}
|
||||
|
||||
visitReactTag.test = function(object, path, state) {
|
||||
return object.type === Syntax.JSXElement;
|
||||
};
|
||||
|
||||
exports.visitorList = [
|
||||
visitReactTag
|
||||
];
|
||||
-126
@@ -1,126 +0,0 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
/*global exports:true*/
|
||||
'use strict';
|
||||
|
||||
var Syntax = require('jstransform').Syntax;
|
||||
var utils = require('jstransform/src/utils');
|
||||
|
||||
function shouldAddDisplayName(object) {
|
||||
if (object &&
|
||||
object.type === Syntax.CallExpression &&
|
||||
object.callee.type === Syntax.MemberExpression &&
|
||||
object.callee.object.type === Syntax.Identifier &&
|
||||
object.callee.object.name === 'React' &&
|
||||
object.callee.property.type === Syntax.Identifier &&
|
||||
object.callee.property.name === 'createClass' &&
|
||||
object.arguments.length === 1 &&
|
||||
object.arguments[0].type === Syntax.ObjectExpression) {
|
||||
// Verify that the displayName property isn't already set
|
||||
var properties = object.arguments[0].properties;
|
||||
var safe = properties.every(function(property) {
|
||||
var value = property.key.type === Syntax.Identifier ?
|
||||
property.key.name :
|
||||
property.key.value;
|
||||
return value !== 'displayName';
|
||||
});
|
||||
return safe;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If `expr` is an Identifier or MemberExpression node made of identifiers and
|
||||
* dot accesses, return a list of the identifier parts. Other nodes return null.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* MyComponent -> ['MyComponent']
|
||||
* namespace.MyComponent -> ['namespace', 'MyComponent']
|
||||
* namespace['foo'] -> null
|
||||
* namespace['foo'].bar -> ['bar']
|
||||
*/
|
||||
function flattenIdentifierOrMemberExpression(expr) {
|
||||
if (expr.type === Syntax.Identifier) {
|
||||
return [expr.name];
|
||||
} else if (expr.type === Syntax.MemberExpression) {
|
||||
if (!expr.computed && expr.property.type === Syntax.Identifier) {
|
||||
var flattenedObject = flattenIdentifierOrMemberExpression(expr.object);
|
||||
if (flattenedObject) {
|
||||
flattenedObject.push(expr.property.name);
|
||||
return flattenedObject;
|
||||
} else {
|
||||
return [expr.property.name];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the following:
|
||||
*
|
||||
* var MyComponent = React.createClass({
|
||||
* render: ...
|
||||
* });
|
||||
*
|
||||
* into:
|
||||
*
|
||||
* var MyComponent = React.createClass({
|
||||
* displayName: 'MyComponent',
|
||||
* render: ...
|
||||
* });
|
||||
*
|
||||
* Also catches:
|
||||
*
|
||||
* MyComponent = React.createClass(...);
|
||||
* namespace.MyComponent = React.createClass(...);
|
||||
* exports.MyComponent = React.createClass(...);
|
||||
* module.exports = {MyComponent: React.createClass(...)};
|
||||
*/
|
||||
function visitReactDisplayName(traverse, object, path, state) {
|
||||
var left, right;
|
||||
|
||||
if (object.type === Syntax.AssignmentExpression) {
|
||||
left = object.left;
|
||||
right = object.right;
|
||||
} else if (object.type === Syntax.Property) {
|
||||
left = object.key;
|
||||
right = object.value;
|
||||
} else if (object.type === Syntax.VariableDeclarator) {
|
||||
left = object.id;
|
||||
right = object.init;
|
||||
}
|
||||
|
||||
if (right && shouldAddDisplayName(right)) {
|
||||
var displayNamePath = flattenIdentifierOrMemberExpression(left);
|
||||
if (displayNamePath) {
|
||||
if (displayNamePath.length > 1 && displayNamePath[0] === 'exports') {
|
||||
displayNamePath.shift();
|
||||
}
|
||||
|
||||
var displayName = displayNamePath.join('.');
|
||||
|
||||
utils.catchup(right.arguments[0].range[0] + 1, state);
|
||||
utils.append('displayName: "' + displayName + '",', state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visitReactDisplayName.test = function(object, path, state) {
|
||||
return (
|
||||
object.type === Syntax.AssignmentExpression ||
|
||||
object.type === Syntax.Property ||
|
||||
object.type === Syntax.VariableDeclarator
|
||||
);
|
||||
};
|
||||
|
||||
exports.visitorList = [
|
||||
visitReactDisplayName
|
||||
];
|
||||
Vendored
-125
@@ -1,125 +0,0 @@
|
||||
/*global exports:true*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var es6ArrowFunctions =
|
||||
require('jstransform/visitors/es6-arrow-function-visitors');
|
||||
var es6Classes = require('jstransform/visitors/es6-class-visitors');
|
||||
var es6Destructuring =
|
||||
require('jstransform/visitors/es6-destructuring-visitors');
|
||||
var es6ObjectConciseMethod =
|
||||
require('jstransform/visitors/es6-object-concise-method-visitors');
|
||||
var es6ObjectShortNotation =
|
||||
require('jstransform/visitors/es6-object-short-notation-visitors');
|
||||
var es6RestParameters = require('jstransform/visitors/es6-rest-param-visitors');
|
||||
var es6Templates = require('jstransform/visitors/es6-template-visitors');
|
||||
var es6CallSpread =
|
||||
require('jstransform/visitors/es6-call-spread-visitors');
|
||||
var es7SpreadProperty =
|
||||
require('jstransform/visitors/es7-spread-property-visitors');
|
||||
var react = require('./transforms/react');
|
||||
var reactDisplayName = require('./transforms/reactDisplayName');
|
||||
var reservedWords = require('jstransform/visitors/reserved-words-visitors');
|
||||
|
||||
/**
|
||||
* Map from transformName => orderedListOfVisitors.
|
||||
*/
|
||||
var transformVisitors = {
|
||||
'es6-arrow-functions': es6ArrowFunctions.visitorList,
|
||||
'es6-classes': es6Classes.visitorList,
|
||||
'es6-destructuring': es6Destructuring.visitorList,
|
||||
'es6-object-concise-method': es6ObjectConciseMethod.visitorList,
|
||||
'es6-object-short-notation': es6ObjectShortNotation.visitorList,
|
||||
'es6-rest-params': es6RestParameters.visitorList,
|
||||
'es6-templates': es6Templates.visitorList,
|
||||
'es6-call-spread': es6CallSpread.visitorList,
|
||||
'es7-spread-property': es7SpreadProperty.visitorList,
|
||||
'react': react.visitorList.concat(reactDisplayName.visitorList),
|
||||
'reserved-words': reservedWords.visitorList
|
||||
};
|
||||
|
||||
var transformSets = {
|
||||
'harmony': [
|
||||
'es6-arrow-functions',
|
||||
'es6-object-concise-method',
|
||||
'es6-object-short-notation',
|
||||
'es6-classes',
|
||||
'es6-rest-params',
|
||||
'es6-templates',
|
||||
'es6-destructuring',
|
||||
'es6-call-spread',
|
||||
'es7-spread-property'
|
||||
],
|
||||
'es3': [
|
||||
'reserved-words'
|
||||
],
|
||||
'react': [
|
||||
'react'
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies the order in which each transform should run.
|
||||
*/
|
||||
var transformRunOrder = [
|
||||
'reserved-words',
|
||||
'es6-arrow-functions',
|
||||
'es6-object-concise-method',
|
||||
'es6-object-short-notation',
|
||||
'es6-classes',
|
||||
'es6-rest-params',
|
||||
'es6-templates',
|
||||
'es6-destructuring',
|
||||
'es6-call-spread',
|
||||
'es7-spread-property',
|
||||
'react'
|
||||
];
|
||||
|
||||
/**
|
||||
* Given a list of transform names, return the ordered list of visitors to be
|
||||
* passed to the transform() function.
|
||||
*
|
||||
* @param {array?} excludes
|
||||
* @return {array}
|
||||
*/
|
||||
function getAllVisitors(excludes) {
|
||||
var ret = [];
|
||||
for (var i = 0, il = transformRunOrder.length; i < il; i++) {
|
||||
if (!excludes || excludes.indexOf(transformRunOrder[i]) === -1) {
|
||||
ret = ret.concat(transformVisitors[transformRunOrder[i]]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of visitor set names, return the ordered list of visitors to be
|
||||
* passed to jstransform.
|
||||
*
|
||||
* @param {array}
|
||||
* @return {array}
|
||||
*/
|
||||
function getVisitorsBySet(sets) {
|
||||
var visitorsToInclude = sets.reduce(function(visitors, set) {
|
||||
if (!transformSets.hasOwnProperty(set)) {
|
||||
throw new Error('Unknown visitor set: ' + set);
|
||||
}
|
||||
transformSets[set].forEach(function(visitor) {
|
||||
visitors[visitor] = true;
|
||||
});
|
||||
return visitors;
|
||||
}, {});
|
||||
|
||||
var visitorList = [];
|
||||
for (var i = 0; i < transformRunOrder.length; i++) {
|
||||
if (visitorsToInclude.hasOwnProperty(transformRunOrder[i])) {
|
||||
visitorList = visitorList.concat(transformVisitors[transformRunOrder[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
return visitorList;
|
||||
}
|
||||
|
||||
exports.getVisitorsBySet = getVisitorsBySet;
|
||||
exports.getAllVisitors = getAllVisitors;
|
||||
exports.transformVisitors = transformVisitors;
|
||||
Vendored
-27
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
Reference in New Issue
Block a user