react-native
Version:
A framework for building native apps using React
113 lines (92 loc) • 3.47 kB
JavaScript
/**
* Copyright (c) 2016-present, 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.
*/
;
const babel = require('babel-core');
const t = babel.types;
const React = {name: 'React'};
const ReactNative = {name: 'ReactNative'};
const platform = {name: 'Platform'};
const os = {name: 'OS'};
const requirePattern = {name: 'require'};
const env = {name: 'env'};
const nodeEnv = {name: 'NODE_ENV'};
const processId = {name: 'process'};
const dev = {name: '__DEV__'};
const importMap = new Map([['ReactNative', 'react-native']]);
const isGlobal = (binding) => !binding;
const isToplevelBinding = (binding) => isGlobal(binding) || !binding.scope.parent;
const isRequireCall = (node, dependencyId, scope) =>
t.isCallExpression(node) &&
t.isIdentifier(node.callee, requirePattern) &&
t.isStringLiteral(node.arguments[0], t.stringLiteral(dependencyId));
const isImport = (node, scope, patterns) =>
patterns.some(pattern => {
const importName = importMap.get(pattern.name) || pattern.name;
return isRequireCall(node, importName, scope);
});
function isImportOrGlobal(node, scope, patterns) {
const identifier = patterns.find(pattern => t.isIdentifier(node, pattern));
return identifier && isToplevelBinding(scope.getBinding(identifier.name)) ||
isImport(node, scope, patterns);
}
const isPlatformOS = (node, scope) =>
t.isIdentifier(node.property, os) &&
isImportOrGlobal(node.object, scope, [platform]);
const isReactPlatformOS = (node, scope) =>
t.isIdentifier(node.property, os) &&
t.isMemberExpression(node.object) &&
t.isIdentifier(node.object.property, platform) &&
isImportOrGlobal(node.object.object, scope, [React, ReactNative]);
const isProcessEnvNodeEnv = (node, scope) =>
t.isIdentifier(node.property, nodeEnv) &&
t.isMemberExpression(node.object) &&
t.isIdentifier(node.object.property, env) &&
t.isIdentifier(node.object.object, processId) &&
isGlobal(scope.getBinding(processId.name));
const isDev = (node, parent, scope) =>
t.isIdentifier(node, dev) &&
isGlobal(scope.getBinding(dev.name)) &&
!(t.isMemberExpression(parent));
const inlinePlugin = {
visitor: {
Identifier(path, state) {
if (isDev(path.node, path.parent, path.scope)) {
path.replaceWith(t.booleanLiteral(state.opts.dev));
}
},
MemberExpression(path, state) {
const node = path.node;
const scope = path.scope;
if (isPlatformOS(node, scope) || isReactPlatformOS(node, scope)) {
path.replaceWith(t.stringLiteral(state.opts.platform));
} else if (isProcessEnvNodeEnv(node, scope)) {
path.replaceWith(
t.stringLiteral(state.opts.dev ? 'development' : 'production'));
}
},
},
};
const plugin = () => inlinePlugin;
function inline(filename, transformResult, options) {
const code = transformResult.code;
const babelOptions = {
filename,
plugins: [[plugin, options]],
inputSourceMap: transformResult.map,
sourceMaps: true,
sourceFileName: filename,
code: false,
babelrc: false,
compact: true,
};
return transformResult.ast
? babel.transformFromAst(transformResult.ast, code, babelOptions)
: babel.transform(code, babelOptions);
}
module.exports = inline;