Remove existing Commands export

Reviewed By: rickhanlonii

Differential Revision: D16039151

fbshipit-source-id: f307697ad44f2ce1471144fc7fd0c38eb5f6c34f
This commit is contained in:
Eli White
2019-07-15 16:54:55 -07:00
committed by Facebook Github Bot
parent 7104c1f3ce
commit c38d6f26e0
5 changed files with 171 additions and 7 deletions
@@ -0,0 +1,79 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
const COMMANDS_EXPORTED_WITH_DIFFERENT_NAME = `
// @flow
const codegenNativeComponent = require('codegenNativeComponent');
import type {ViewProps} from 'ViewPropTypes';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
interface NativeCommands {
+hotspotUpdate: (viewRef: React.Ref<'Module'>) => void;
}
export const Foo = codegenNativeCommands<NativeCommands>();
export default codegenNativeComponent<ModuleProps>('Module');
`;
const OTHER_COMMANDS_EXPORT = `
// @flow
const codegenNativeComponent = require('codegenNativeComponent');
import type {ViewProps} from 'ViewPropTypes';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
interface NativeCommands {
+hotspotUpdate: (viewRef: React.Ref<'Module'>) => void;
}
export const Commands = 4;
export default codegenNativeComponent<ModuleProps>('Module');
`;
const COMMANDS_EXPORTED_WITH_SHORTHAND = `
// @flow
const codegenNativeComponent = require('codegenNativeComponent');
import type {ViewProps} from 'ViewPropTypes';
type ModuleProps = $ReadOnly<{|
...ViewProps,
|}>;
interface NativeCommands {
+hotspotUpdate: (viewRef: React.Ref<'Module'>) => void;
}
const Commands = 4;
export {Commands};
export default codegenNativeComponent<ModuleProps>('Module');
`;
module.exports = {
'CommandsExportedWithDifferentNameNativeComponent.js': COMMANDS_EXPORTED_WITH_DIFFERENT_NAME,
'CommandsExportedWithShorthandNativeComponent.js': COMMANDS_EXPORTED_WITH_SHORTHAND,
'OtherCommandsExportNativeComponent.js': OTHER_COMMANDS_EXPORT,
};
@@ -19,7 +19,6 @@ type ModuleProps = $ReadOnly<{| ...ViewProps,
onDirectEventDefinedInlineNull: DirectEventHandler<null>,
onBubblingEventDefinedInlineNull: BubblingEventHandler<null>,
|}>;
export const Commands = codegenNativeCommands<NativeCommands>();
const registerGeneratedViewConfig = require('registerGeneratedViewConfig');
@@ -73,3 +72,9 @@ exports[`Babel plugin inline view configs can inline config for NotANativeCompon
export default 'Not a view config';"
`;
exports[`Babel plugin inline view configs fails on inline config for CommandsExportedWithDifferentNameNativeComponent.js 1`] = `"Native commands must be exported with the name 'Commands'"`;
exports[`Babel plugin inline view configs fails on inline config for CommandsExportedWithShorthandNativeComponent.js 1`] = `"'Commands' is a reserved export and may only be used to export the result of codegenNativeCommands."`;
exports[`Babel plugin inline view configs fails on inline config for OtherCommandsExportNativeComponent.js 1`] = `"'Commands' is a reserved export and may only be used to export the result of codegenNativeCommands."`;
@@ -12,9 +12,10 @@
const {transform: babelTransform} = require('@babel/core');
const fixtures = require('../__test_fixtures__/fixtures.js');
const failures = require('../__test_fixtures__/failures.js');
function transform(filename) {
return babelTransform(fixtures[filename], {
function transform(fixture, filename) {
return babelTransform(fixture, {
plugins: [require('@babel/plugin-syntax-flow'), require('../index')],
babelrc: false,
filename,
@@ -26,7 +27,17 @@ describe('Babel plugin inline view configs', () => {
.sort()
.forEach(fixtureName => {
it(`can inline config for ${fixtureName}`, () => {
expect(transform(fixtureName)).toMatchSnapshot();
expect(transform(fixtures[fixtureName], fixtureName)).toMatchSnapshot();
});
});
Object.keys(failures)
.sort()
.forEach(fixtureName => {
it(`fails on inline config for ${fixtureName}`, () => {
expect(() => {
transform(failures[fixtureName], fixtureName);
}).toThrowErrorMatchingSnapshot();
});
});
});
@@ -51,14 +51,83 @@ module.exports = function(context) {
pre(state) {
this.code = state.code;
this.filename = state.opts.filename;
this.defaultExport = null;
this.commandsExport = null;
this.codeInserted = false;
},
visitor: {
ExportNamedDeclaration(nodePath) {
if (this.codeInserted) {
return;
}
if (
nodePath.node.declaration &&
nodePath.node.declaration.declarations &&
nodePath.node.declaration.declarations[0]
) {
const firstDeclaration = nodePath.node.declaration.declarations[0];
if (firstDeclaration.type === 'VariableDeclarator') {
if (
firstDeclaration.init.type === 'CallExpression' &&
firstDeclaration.init.callee.type === 'Identifier' &&
firstDeclaration.init.callee.name === 'codegenNativeCommands'
) {
if (
firstDeclaration.id.type === 'Identifier' &&
firstDeclaration.id.name !== 'Commands'
) {
throw new Error(
"Native commands must be exported with the name 'Commands'",
);
}
this.commandsExport = nodePath;
return;
} else {
if (firstDeclaration.id.name === 'Commands') {
throw new Error(
"'Commands' is a reserved export and may only be used to export the result of codegenNativeCommands.",
);
}
}
}
} else if (
nodePath.node.specifiers &&
nodePath.node.specifiers.length > 0
) {
nodePath.node.specifiers.forEach(specifier => {
if (
specifier.type === 'ExportSpecifier' &&
specifier.local.type === 'Identifier' &&
specifier.local.name === 'Commands'
) {
throw new Error(
"'Commands' is a reserved export and may only be used to export the result of codegenNativeCommands.",
);
}
});
}
},
ExportDefaultDeclaration(nodePath, state) {
if (isCodegenDeclaration(nodePath.node.declaration)) {
const viewConfig = generateViewConfig(this.filename, this.code);
nodePath.replaceWithMultiple(context.parse(viewConfig).program.body);
this.defaultExport = nodePath;
}
},
Program: {
exit() {
if (this.defaultExport) {
const viewConfig = generateViewConfig(this.filename, this.code);
this.defaultExport.replaceWithMultiple(
context.parse(viewConfig).program.body,
);
if (this.commandsExport != null) {
this.commandsExport.remove();
}
this.codeInserted = true;
}
},
},
},
};
};
@@ -1,5 +1,5 @@
{
"version": "0.0.1",
"version": "0.0.2",
"name": "babel-plugin-inline-view-configs",
"description": "Babel plugin to inline view configs for React Native",
"repository": {