babel-plugin-react-transform
Advanced tools
Comparing version 1.0.5 to 1.1.0
119
lib/index.js
@@ -43,2 +43,4 @@ 'use strict'; | ||
var wrapComponentIdKey = '__reactTransformWrapComponentId'; | ||
var optionsKey = '__reactTransformOptions'; | ||
var cacheKey = '__reactTransformCache'; | ||
@@ -56,11 +58,74 @@ function isRenderMethod(member) { | ||
var isCreateClassCallExpression = t.buildMatchMemberExpression('React.createClass'); | ||
function buildIsCreateClassCallExpression(factoryMethods) { | ||
var matchMemberExpressions = {}; | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = factoryMethods[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var method = _step.value; | ||
matchMemberExpressions[method] = t.buildMatchMemberExpression(method); | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator['return']) { | ||
_iterator['return'](); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
return function (node) { | ||
var _iteratorNormalCompletion2 = true; | ||
var _didIteratorError2 = false; | ||
var _iteratorError2 = undefined; | ||
try { | ||
for (var _iterator2 = factoryMethods[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | ||
var method = _step2.value; | ||
if (method.indexOf('.') !== -1) { | ||
if (matchMemberExpressions[method](node.callee)) { | ||
return true; | ||
} | ||
} else { | ||
if (node.callee.name === method) { | ||
return true; | ||
} | ||
} | ||
} | ||
} catch (err) { | ||
_didIteratorError2 = true; | ||
_iteratorError2 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion2 && _iterator2['return']) { | ||
_iterator2['return'](); | ||
} | ||
} finally { | ||
if (_didIteratorError2) { | ||
throw _iteratorError2; | ||
} | ||
} | ||
} | ||
}; | ||
} | ||
/** | ||
* Does this node look like a createClass() call? | ||
*/ | ||
function isCreateClass(node) { | ||
function isCreateClass(node, isCreateClassCallExpression) { | ||
if (!node || !t.isCallExpression(node)) { | ||
return false; | ||
} | ||
if (!isCreateClassCallExpression(node.callee)) { | ||
if (!isCreateClassCallExpression(node)) { | ||
return false; | ||
@@ -99,2 +164,15 @@ } | ||
function isValidOptions(options) { | ||
return typeof options === 'object' && Array.isArray(options.transforms); | ||
} | ||
var didWarnAboutLegacyConfig = false; | ||
function warnOnceAboutLegacyConfig() { | ||
if (didWarnAboutLegacyConfig) { | ||
return; | ||
} | ||
console.warn('Warning: you are using an outdated format of React Transform configuration. ' + 'Please update your configuration to the new format. See the Releases page for migration instructions: ' + 'https://github.com/gaearon/babel-plugin-react-transform/releases'); | ||
didWarnAboutLegacyConfig = true; | ||
} | ||
/** | ||
@@ -107,6 +185,16 @@ * Enforces plugin options to be defined and returns them. | ||
} | ||
var pluginOptions = file.opts.extra['react-transform']; | ||
if (!Array.isArray(pluginOptions)) { | ||
throw new Error('babel-plugin-react-transform requires that you specify ' + 'extras["react-transform"] in .babelrc ' + 'or in your Babel Node API call options, and that it is an array.'); | ||
if (Array.isArray(pluginOptions)) { | ||
warnOnceAboutLegacyConfig(); | ||
var transforms = pluginOptions.map(function (option) { | ||
option.transform = option.transform || option.target; | ||
return option; | ||
}); | ||
pluginOptions = { transforms: transforms }; | ||
} | ||
if (!isValidOptions(pluginOptions)) { | ||
throw new Error('babel-plugin-react-transform requires that you specify ' + 'extras["react-transform"] in .babelrc ' + 'or in your Babel Node API call options, and that it is an object with ' + 'a transforms property which is an array.'); | ||
} | ||
return pluginOptions; | ||
@@ -136,3 +224,3 @@ } | ||
* Memorizes the fact that we have visited a valid component in the plugin state. | ||
* We will later retrieved memorized records to compose an object out of them. | ||
* We will later retrieve memorized records to compose an object out of them. | ||
*/ | ||
@@ -177,3 +265,3 @@ function addComponentRecord(node, scope, file, state) { | ||
var id = scope.generateUidIdentifier('reactComponentWrapper'); | ||
var target = targetOptions.target; | ||
var transform = targetOptions.transform; | ||
var _targetOptions$imports = targetOptions.imports; | ||
@@ -200,3 +288,3 @@ var imports = _targetOptions$imports === undefined ? [] : _targetOptions$imports; | ||
return [id, t.variableDeclaration('var', [t.variableDeclarator(id, t.callExpression(file.addImport(resolvePath(target, filename)), [t.objectExpression([t.property('init', t.identifier('filename'), t.literal(filename)), t.property('init', t.identifier('components'), recordsId), t.property('init', t.identifier('locals'), t.arrayExpression(locals.map(function (local) { | ||
return [id, t.variableDeclaration('var', [t.variableDeclarator(id, t.callExpression(file.addImport(resolvePath(transform, filename)), [t.objectExpression([t.property('init', t.identifier('filename'), t.literal(filename)), t.property('init', t.identifier('components'), recordsId), t.property('init', t.identifier('locals'), t.arrayExpression(locals.map(function (local) { | ||
return t.identifier(local); | ||
@@ -246,3 +334,5 @@ }))), t.property('init', t.identifier('imports'), t.arrayExpression(imports.map(function (imp) { | ||
exit: function exit(node, parent, scope, file) { | ||
if (!isCreateClass(node)) { | ||
var isCreateClassCallExpression = this.state[cacheKey].isCreateClassCallExpression; | ||
if (!isCreateClass(node, isCreateClassCallExpression)) { | ||
return; | ||
@@ -260,2 +350,9 @@ } | ||
enter: function enter(node, parent, scope, file) { | ||
var options = getPluginOptions(file); | ||
var factoryMethods = options.factoryMethods || ['React.createClass', 'createClass']; | ||
this.state[optionsKey] = options; | ||
this.state[cacheKey] = { | ||
isCreateClassCallExpression: buildIsCreateClassCallExpression(factoryMethods) | ||
}; | ||
this.state[wrapComponentIdKey] = scope.generateUidIdentifier('wrapComponent'); | ||
@@ -270,3 +367,3 @@ }, | ||
// Generate a variable holding component records | ||
var allTransformOptions = getPluginOptions(file); | ||
var allTransforms = this.state[optionsKey].transforms; | ||
@@ -281,3 +378,3 @@ var _defineComponentRecords = defineComponentRecords(scope, this.state); | ||
// Import transformation functions and initialize them | ||
var initTransformCalls = allTransformOptions.map(function (transformOptions) { | ||
var initTransformCalls = allTransforms.map(function (transformOptions) { | ||
return defineInitTransformCall(scope, file, recordsId, transformOptions); | ||
@@ -284,0 +381,0 @@ }).filter(Boolean); |
{ | ||
"name": "babel-plugin-react-transform", | ||
"version": "1.0.5", | ||
"version": "1.1.0", | ||
"description": "Babel plugin to instrument React components with custom transforms", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
@@ -9,5 +9,6 @@ # babel-plugin-react-transform | ||
* catch errors inside `render()` like **[react-transform-catch-errors](https://github.com/gaearon/react-transform-catch-errors)**; | ||
* enable hot reloading like **[react-transform-webpack-hmr](https://github.com/gaearon/react-transform-webpack-hmr)**; | ||
* enable hot reloading like **[react-transform-hmr](https://github.com/gaearon/react-transform-hmr)**; | ||
* render an inline prop inspector like **[react-transform-debug-inspector](https://github.com/alexkuz/react-transform-debug-inspector)**; | ||
* highlight parts of the screen when components update (want to write this one?), | ||
* highlight parts of the screen when components update like | ||
**[react-transform-render-visualizer](https://github.com/spredfast/react-transform-render-visualizer)**; | ||
* etc. | ||
@@ -37,3 +38,3 @@ | ||
``` | ||
npm install --save-dev react-transform-webpack-hmr | ||
npm install --save-dev react-transform-hmr | ||
npm install --save-dev react-transform-catch-errors | ||
@@ -43,3 +44,3 @@ ``` | ||
Then edit your `.babelrc` to include `extra.react-transform`. | ||
It must be an array of the transforms you want to use: | ||
It must be an object with a `transforms` property being an array of the transforms you want to use: | ||
@@ -61,17 +62,23 @@ ```js | ||
"extra": { | ||
// must be defined and be an array | ||
"react-transform": [{ | ||
// can be an NPM module name or a local path | ||
"target": "react-transform-webpack-hmr", | ||
// see specific transform's docs for "imports" and "locals" it needs | ||
"imports": ["react"], | ||
"locals": ["module"] | ||
}, { | ||
// you can have many transforms, not just one | ||
"target": "react-transform-catch-errors", | ||
"imports": ["react", "redbox-react"] | ||
}, { | ||
// can be an NPM module name or a local path | ||
"target": "./src/my-custom-transform" | ||
}] | ||
// must be an object | ||
"react-transform": { | ||
// must be an array | ||
"transforms": [{ | ||
// can be an NPM module name or a local path | ||
"transform": "react-transform-hmr", | ||
// see specific transform's docs for "imports" and "locals" it needs | ||
"imports": ["react"], | ||
"locals": ["module"] | ||
}, { | ||
// you can have many transforms, not just one | ||
"transform": "react-transform-catch-errors", | ||
"imports": ["react", "redbox-react"] | ||
}, { | ||
// can be an NPM module name or a local path | ||
"transform": "./src/my-custom-transform" | ||
}] | ||
}, | ||
// by default we only look for `React.createClass` (and ES6 classes) | ||
// but you can tell the plugin to look for different component factories: | ||
// factoryMethods: ["React.createClass", "createClass"] | ||
} | ||
@@ -83,4 +90,8 @@ } | ||
As you can see each transform, apart from the `target` field where you write it name, also has `imports` and `locals` fields. You should consult the docs of each individual transform to learn which `imports` and `locals` it might need, and how it uses them. You probably already guessed that this is just a way to inject local variables (like `module`) or dependencies (like `react`) into the transforms that need them. | ||
As you can see each transform, apart from the `transform` field where you write it name, also has `imports` and `locals` fields. You should consult the docs of each individual transform to learn which `imports` and `locals` it might need, and how it uses them. You probably already guessed that this is just a way to inject local variables (like `module`) or dependencies (like `react`) into the transforms that need them. | ||
Note that when using `React.createClass()` and allowing `babel` to extract the `displayName` property you must ensure that [babel-plugin-react-display-name](https://github.com/babel/babel/tree/development/packages/babel-plugin-react-display-name) is included before `react-transform`. See [this github issue](https://github.com/gaearon/babel-plugin-react-transform/issues/19) for more details. | ||
You may optionally specify an array of strings called `factoryMethods` if you want the plugin to look for components created with a factory method other than `React.createClass`. Note that you don’t have to do anything special to look for ES6 components—`factoryMethods` is only relevant if you use factory methods akin to `React.createClass`. | ||
## Writing a Transform | ||
@@ -201,3 +212,3 @@ | ||
* **https://github.com/gaearon/react-transform-boilerplate** | ||
* **https://github.com/gaearon/react-transform-webpack-hmr** | ||
* **https://github.com/gaearon/react-transform-hmr** | ||
* **https://github.com/gaearon/react-transform-catch-errors** | ||
@@ -207,8 +218,2 @@ * **https://github.com/alexkuz/react-transform-debug-inspector** | ||
## Limitations | ||
Currently, it can only locate components of two types: ES6 classes with `render` method and explicit `React.createClass()` calls. I’m open to adding more heuristics for other common patterns, given enough interest. | ||
When using `React.createClass()` and allowing `babel` to extract the `displayName` property you must ensure that [babel-plugin-react-display-name](https://github.com/babel/babel/tree/development/packages/babel-plugin-react-display-name) is included before `react-transform`. See [this github issue](https://github.com/gaearon/babel-plugin-react-transform/issues/19) for more details. | ||
## Discussion | ||
@@ -215,0 +220,0 @@ |
@@ -17,14 +17,4 @@ import path from 'path'; | ||
const actualPath = path.join(fixtureDir, 'actual.js'); | ||
const actual = transformFileSync(actualPath, { | ||
plugins: [plugin], | ||
extra: { | ||
'react-transform': [{ | ||
target: 'my-custom-module/wrap', | ||
locals: ['module'], | ||
imports: ['react'] | ||
}, { | ||
target: 'my-other-custom-module/wrap' | ||
}] | ||
} | ||
}).code; | ||
const actual = transformFileSync(actualPath).code; | ||
const expected = fs.readFileSync( | ||
@@ -31,0 +21,0 @@ path.join(fixtureDir, 'expected.js') |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
47693
23
941
228