GT2/GT2-Android/node_modules/babel-plugin-react-transform/lib/index.js

345 lines
12 KiB
JavaScript

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
exports.default = function (_ref) {
var t = _ref.types;
var template = _ref.template;
function matchesPatterns(path, patterns) {
return !!(0, _find2.default)(patterns, function (pattern) {
return t.isIdentifier(path.node, { name: pattern }) || path.matchesPattern(pattern);
});
}
function isReactLikeClass(node) {
return !!(0, _find2.default)(node.body.body, function (classMember) {
return t.isClassMethod(classMember) && t.isIdentifier(classMember.key, { name: 'render' });
});
}
function isReactLikeComponentObject(node) {
return t.isObjectExpression(node) && !!(0, _find2.default)(node.properties, function (objectMember) {
return (t.isObjectProperty(objectMember) || t.isObjectMethod(objectMember)) && (t.isIdentifier(objectMember.key, { name: 'render' }) || t.isStringLiteral(objectMember.key, { value: 'render' }));
});
}
// `foo({ displayName: 'NAME' });` => 'NAME'
function getDisplayName(node) {
var property = (0, _find2.default)(node.arguments[0].properties, function (node) {
return node.key.name === 'displayName';
});
return property && property.value.value;
}
function hasParentFunction(path) {
return !!path.findParent(function (parentPath) {
return parentPath.isFunction();
});
}
// wrapperFunction("componentId")(node)
function wrapComponent(node, componentId, wrapperFunctionId) {
return t.callExpression(t.callExpression(wrapperFunctionId, [t.stringLiteral(componentId)]), [node]);
}
// `{ name: foo }` => Node { type: "ObjectExpression", properties: [...] }
function toObjectExpression(object) {
var properties = Object.keys(object).map(function (key) {
return t.objectProperty(t.identifier(key), object[key]);
});
return t.objectExpression(properties);
}
var wrapperFunctionTemplate = template('\n function WRAPPER_FUNCTION_ID(ID_PARAM) {\n return function(COMPONENT_PARAM) {\n return EXPRESSION;\n };\n }\n ');
var VISITED_KEY = 'react-transform-' + Date.now();
var componentVisitor = {
Class: function Class(path) {
if (path.node[VISITED_KEY] || !matchesPatterns(path.get('superClass'), this.superClasses) || !isReactLikeClass(path.node)) {
return;
}
path.node[VISITED_KEY] = true;
var componentName = path.node.id && path.node.id.name || null;
var componentId = componentName || path.scope.generateUid('component');
var isInFunction = hasParentFunction(path);
this.components.push({
id: componentId,
name: componentName,
isInFunction: isInFunction
});
// Can't wrap ClassDeclarations
var isStatement = t.isStatement(path.node);
var expression = t.toExpression(path.node);
// wrapperFunction("componentId")(node)
var wrapped = wrapComponent(expression, componentId, this.wrapperFunctionId);
var constId = void 0;
if (isStatement) {
// wrapperFunction("componentId")(class Foo ...) => const Foo = wrapperFunction("componentId")(class Foo ...)
constId = t.identifier(componentName || componentId);
wrapped = t.variableDeclaration('const', [t.variableDeclarator(constId, wrapped)]);
}
if (t.isExportDefaultDeclaration(path.parent)) {
path.parentPath.insertBefore(wrapped);
path.parent.declaration = constId;
} else {
path.replaceWith(wrapped);
}
},
CallExpression: function CallExpression(path) {
if (path.node[VISITED_KEY] || !matchesPatterns(path.get('callee'), this.factoryMethods) || !isReactLikeComponentObject(path.node.arguments[0])) {
return;
}
path.node[VISITED_KEY] = true;
// `foo({ displayName: 'NAME' });` => 'NAME'
var componentName = getDisplayName(path.node);
var componentId = componentName || path.scope.generateUid('component');
var isInFunction = hasParentFunction(path);
this.components.push({
id: componentId,
name: componentName,
isInFunction: isInFunction
});
path.replaceWith(wrapComponent(path.node, componentId, this.wrapperFunctionId));
}
};
var ReactTransformBuilder = function () {
function ReactTransformBuilder(file, options) {
_classCallCheck(this, ReactTransformBuilder);
this.file = file;
this.program = file.path;
this.options = this.normalizeOptions(options);
// @todo: clean this shit up
this.configuredTransformsIds = [];
}
_createClass(ReactTransformBuilder, [{
key: 'normalizeOptions',
value: function normalizeOptions(options) {
return {
factoryMethods: options.factoryMethods || ['React.createClass'],
superClasses: options.superClasses || ['React.Component', 'React.PureComponent', 'Component', 'PureComponent'],
transforms: options.transforms.map(function (opts) {
return {
transform: opts.transform,
locals: opts.locals || [],
imports: opts.imports || []
};
})
};
}
}, {
key: 'build',
value: function build() {
var componentsDeclarationId = this.file.scope.generateUidIdentifier('components');
var wrapperFunctionId = this.file.scope.generateUidIdentifier('wrapComponent');
var components = this.collectAndWrapComponents(wrapperFunctionId);
if (!components.length) {
return;
}
var componentsDeclaration = this.initComponentsDeclaration(componentsDeclarationId, components);
var configuredTransforms = this.initTransformers(componentsDeclarationId);
var wrapperFunction = this.initWrapperFunction(wrapperFunctionId);
var body = this.program.node.body;
body.unshift(wrapperFunction);
configuredTransforms.reverse().forEach(function (node) {
return body.unshift(node);
});
body.unshift(componentsDeclaration);
}
/**
* const Foo = _wrapComponent('Foo')(class Foo extends React.Component {});
* ...
* const Bar = _wrapComponent('Bar')(React.createClass({
* displayName: 'Bar'
* }));
*/
}, {
key: 'collectAndWrapComponents',
value: function collectAndWrapComponents(wrapperFunctionId) {
var components = [];
this.file.path.traverse(componentVisitor, {
wrapperFunctionId: wrapperFunctionId,
components: components,
factoryMethods: this.options.factoryMethods,
superClasses: this.options.superClasses,
currentlyInFunction: false
});
return components;
}
/**
* const _components = {
* Foo: {
* displayName: "Foo"
* }
* };
*/
}, {
key: 'initComponentsDeclaration',
value: function initComponentsDeclaration(componentsDeclarationId, components) {
var uniqueId = 0;
var props = components.map(function (component) {
var componentId = component.id;
var componentProps = [];
if (component.name) {
componentProps.push(t.objectProperty(t.identifier('displayName'), t.stringLiteral(component.name)));
}
if (component.isInFunction) {
componentProps.push(t.objectProperty(t.identifier('isInFunction'), t.booleanLiteral(true)));
}
var objectKey = void 0;
if (t.isValidIdentifier(componentId)) {
objectKey = t.identifier(componentId);
} else {
objectKey = t.stringLiteral(componentId);
}
return t.objectProperty(objectKey, t.objectExpression(componentProps));
});
return t.variableDeclaration('const', [t.variableDeclarator(componentsDeclarationId, t.objectExpression(props))]);
}
/**
* import _transformLib from "transform-lib";
* ...
* const _transformLib2 = _transformLib({
* filename: "filename",
* components: _components,
* locals: [],
* imports: []
* });
*/
}, {
key: 'initTransformers',
value: function initTransformers(componentsDeclarationId) {
var _this = this;
return this.options.transforms.map(function (transform) {
var transformName = transform.transform;
var transformImportId = _this.file.addImport(transformName, 'default', transformName);
var transformLocals = transform.locals.map(function (local) {
return t.identifier(local);
});
var transformImports = transform.imports.map(function (importName) {
return _this.file.addImport(importName, 'default', importName);
});
var configuredTransformId = _this.file.scope.generateUidIdentifier(transformName);
var configuredTransform = t.variableDeclaration('const', [t.variableDeclarator(configuredTransformId, t.callExpression(transformImportId, [toObjectExpression({
filename: t.stringLiteral(_this.file.opts.filename),
components: componentsDeclarationId,
locals: t.arrayExpression(transformLocals),
imports: t.arrayExpression(transformImports)
})]))]);
_this.configuredTransformsIds.push(configuredTransformId);
return configuredTransform;
});
}
/**
* function _wrapComponent(id) {
* return function (Component) {
* return _transformLib2(Component, id);
* };
* }
*/
}, {
key: 'initWrapperFunction',
value: function initWrapperFunction(wrapperFunctionId) {
var idParam = t.identifier('id');
var componentParam = t.identifier('Component');
var expression = this.configuredTransformsIds.reverse().reduce(function (memo, transformId) {
return t.callExpression(transformId, [memo, idParam]);
}, componentParam);
return wrapperFunctionTemplate({
WRAPPER_FUNCTION_ID: wrapperFunctionId,
ID_PARAM: idParam,
COMPONENT_PARAM: componentParam,
EXPRESSION: expression
});
}
}], [{
key: 'validateOptions',
value: function validateOptions(options) {
return (typeof options === 'undefined' ? 'undefined' : _typeof(options)) === 'object' && Array.isArray(options.transforms);
}
}, {
key: 'assertValidOptions',
value: function assertValidOptions(options) {
if (!ReactTransformBuilder.validateOptions(options)) {
throw new Error('babel-plugin-react-transform requires that you specify options ' + 'in .babelrc or from the Babel Node API, and that it is an object ' + 'with a transforms property which is an array.');
}
}
}]);
return ReactTransformBuilder;
}();
return {
visitor: {
Program: function Program(path, _ref2) {
var file = _ref2.file;
var opts = _ref2.opts;
ReactTransformBuilder.assertValidOptions(opts);
var builder = new ReactTransformBuilder(file, opts);
builder.build();
}
}
};
};
var _find = require('lodash/find');
var _find2 = _interopRequireDefault(_find);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }