inline `Platform.select`
Summary: We are already inlining `Platform.OS`. This diff adds support to inline calls to `Platform.select` with an object literal as first argument. The transform will replace the call with the property value corresponding to the platform, or `undefined` if it does not exist. Reviewed By: frantic Differential Revision: D3385391 fbshipit-source-id: bb068d17948ed84e381707faeaa0450399c2f306
This commit is contained in:
parent
1facfb77da
commit
8c3db9782e
|
@ -141,6 +141,113 @@ describe('inline constants', () => {
|
|||
normalize(code.replace(/require\('react-native'\)\.Platform\.OS/, '"android"')));
|
||||
});
|
||||
|
||||
it('inlines Platform.select in the code if Platform is a global and the argument is an object literal', () => {
|
||||
const code = `function a() {
|
||||
var a = Platform.select({ios: 1, android: 2});
|
||||
var b = a.Platform.select({ios: 1, android: 2});
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'});
|
||||
expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.select[^;]+/, '1')));
|
||||
});
|
||||
|
||||
it('replaces Platform.select in the code if Platform is a top level import', () => {
|
||||
const code = `
|
||||
var Platform = require('Platform');
|
||||
function a() {
|
||||
Platform.select({ios: 1, android: 2});
|
||||
var b = a.Platform.select({});
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'android'});
|
||||
expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.select[^;]+/, '2')));
|
||||
});
|
||||
|
||||
it('replaces Platform.select in the code if Platform is a top level import from react-native', () => {
|
||||
const code = `
|
||||
var Platform = require('react-native').Platform;
|
||||
function a() {
|
||||
Platform.select({ios: 1, android: 2});
|
||||
var b = a.Platform.select({});
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'});
|
||||
expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.select[^;]+/, '1')));
|
||||
});
|
||||
|
||||
it('replaces require("Platform").select in the code', () => {
|
||||
const code = `function a() {
|
||||
var a = require('Platform').select({ios: 1, android: 2});
|
||||
var b = a.require('Platform').select({});
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'android'});
|
||||
expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.select[^;]+/, '2')));
|
||||
});
|
||||
|
||||
it('replaces React.Platform.select in the code if React is a global', () => {
|
||||
const code = `function a() {
|
||||
var a = React.Platform.select({ios: 1, android: 2});
|
||||
var b = a.React.Platform.select({});
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'});
|
||||
expect(toString(ast)).toEqual(normalize(code.replace(/React\.Platform\.select[^;]+/, '1')));
|
||||
});
|
||||
|
||||
it('replaces ReactNative.Platform.select in the code if ReactNative is a global', () => {
|
||||
const code = `function a() {
|
||||
var a = ReactNative.Platform.select({ios: 1, android: 2});
|
||||
var b = a.ReactNative.Platform.select({});
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'});
|
||||
expect(toString(ast)).toEqual(normalize(code.replace(/ReactNative\.Platform\.select[^;]+/, '1')));
|
||||
});
|
||||
|
||||
it('replaces React.Platform.select in the code if React is a top level import', () => {
|
||||
const code = `
|
||||
var React = require('React');
|
||||
function a() {
|
||||
var a = React.Platform.select({ios: 1, android: 2});
|
||||
var b = a.React.Platform.select({});
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'});
|
||||
expect(toString(ast)).toEqual(normalize(code.replace(/React\.Platform\.select[^;]+/, '1')));
|
||||
});
|
||||
|
||||
it('replaces require("React").Platform.select in the code', () => {
|
||||
const code = `function a() {
|
||||
var a = require('React').Platform.select({ios: 1, android: 2});
|
||||
var b = a.require('React').Platform.select({});
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'android'});
|
||||
expect(toString(ast)).toEqual(
|
||||
normalize(code.replace(/require\('React'\)\.Platform\.select[^;]+/, '2')));
|
||||
});
|
||||
|
||||
it('replaces ReactNative.Platform.select in the code if ReactNative is a top level import', () => {
|
||||
const code = `
|
||||
var ReactNative = require('react-native');
|
||||
function a() {
|
||||
var a = ReactNative.Plaftform.select({ios: 1, android: 2});
|
||||
var b = a.ReactNative.Platform.select;
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'android'});
|
||||
expect(toString(ast)).toEqual(normalize(code.replace(/ReactNative.Platform\.select[^;]+/, '2')));
|
||||
});
|
||||
|
||||
it('replaces require("react-native").Platform.select in the code', () => {
|
||||
const code = `
|
||||
var a = require('react-native').Platform.select({ios: 1, android: 2});
|
||||
var b = a.require('react-native').Platform.select({});
|
||||
`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'android'});
|
||||
expect(toString(ast)).toEqual(
|
||||
normalize(code.replace(/require\('react-native'\)\.Platform\.select[^;]+/, '2')));
|
||||
});
|
||||
|
||||
it('replaces non-existing properties with `undefined`', () => {
|
||||
const code = 'var a = Platform.select({ios: 1, android: 2})';
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'doesnotexist'});
|
||||
expect(toString(ast)).toEqual(
|
||||
normalize(code.replace(/Platform\.select[^;]+/, 'undefined')));
|
||||
});
|
||||
|
||||
it('replaces process.env.NODE_ENV in the code', () => {
|
||||
const code = `function a() {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
|
|
|
@ -15,6 +15,7 @@ const React = {name: 'React'};
|
|||
const ReactNative = {name: 'ReactNative'};
|
||||
const platform = {name: 'Platform'};
|
||||
const os = {name: 'OS'};
|
||||
const select = {name: 'select'};
|
||||
const requirePattern = {name: 'require'};
|
||||
|
||||
const env = {name: 'env'};
|
||||
|
@ -63,11 +64,29 @@ const isProcessEnvNodeEnv = (node, scope) =>
|
|||
t.isIdentifier(node.object.object, processId) &&
|
||||
isGlobal(scope.getBinding(processId.name));
|
||||
|
||||
const isPlatformSelect = (node, scope) =>
|
||||
t.isMemberExpression(node.callee) &&
|
||||
t.isIdentifier(node.callee.object, platform) &&
|
||||
t.isIdentifier(node.callee.property, select) &&
|
||||
isImportOrGlobal(node.callee.object, scope, [platform]);
|
||||
|
||||
const isReactPlatformSelect = (node, scope) =>
|
||||
t.isMemberExpression(node.callee) &&
|
||||
t.isIdentifier(node.callee.property, select) &&
|
||||
t.isMemberExpression(node.callee.object) &&
|
||||
t.isIdentifier(node.callee.object.property, platform) &&
|
||||
isImportOrGlobal(node.callee.object.object, scope, [React, ReactNative]);
|
||||
|
||||
const isDev = (node, parent, scope) =>
|
||||
t.isIdentifier(node, dev) &&
|
||||
isGlobal(scope.getBinding(dev.name)) &&
|
||||
!(t.isMemberExpression(parent));
|
||||
|
||||
function findProperty(objectExpression, key) {
|
||||
const property = objectExpression.properties.find(p => p.key.name === key);
|
||||
return property ? property.value : t.identifier('undefined');
|
||||
}
|
||||
|
||||
const inlinePlugin = {
|
||||
visitor: {
|
||||
Identifier(path, state) {
|
||||
|
@ -86,6 +105,19 @@ const inlinePlugin = {
|
|||
t.stringLiteral(state.opts.dev ? 'development' : 'production'));
|
||||
}
|
||||
},
|
||||
CallExpression(path, state) {
|
||||
const node = path.node;
|
||||
const scope = path.scope;
|
||||
const arg = node.arguments[0];
|
||||
|
||||
if (isPlatformSelect(node, scope) || isReactPlatformSelect(node, scope)) {
|
||||
const replacement = t.isObjectExpression(arg)
|
||||
? findProperty(arg, state.opts.platform)
|
||||
: node;
|
||||
|
||||
path.replaceWith(replacement);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue