Change module parser to consider extends instead of default exports
Summary: Following out internal communication we decided to change logic of current parser to consider types which extend 'TurboModule' instead of looking at default exports. It also cassed for minor changes i n testing logic and updating snapshots. Reviewed By: rickhanlonii Differential Revision: D16200939 fbshipit-source-id: a21cbfc461647df2b9210c0eca4c2c95c285dfe1
This commit is contained in:
Родитель
4d50f5f4b8
Коммит
cbd4ad43c0
|
@ -14,6 +14,7 @@ import type {SchemaType} from '../../CodegenSchema.js';
|
|||
// $FlowFixMe there's no flowtype flow-parser
|
||||
const flowParser = require('flow-parser');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const {buildModuleSchema} = require('./modules/schema');
|
||||
const {buildComponentSchema} = require('./components/schema');
|
||||
const {processComponent} = require('./components');
|
||||
|
@ -35,46 +36,79 @@ function getTypes(ast) {
|
|||
}, {});
|
||||
}
|
||||
|
||||
function getConfigType(ast): 'module' | 'component' {
|
||||
function getConfigType(ast, types): 'module' | 'component' {
|
||||
const defaultExports = ast.body.filter(
|
||||
node => node.type === 'ExportDefaultDeclaration',
|
||||
);
|
||||
if (defaultExports.length !== 1) {
|
||||
throw new Error('File should contain only one default export.');
|
||||
const isComponent =
|
||||
defaultExports[0] &&
|
||||
defaultExports[0].declaration &&
|
||||
defaultExports[0].declaration.callee &&
|
||||
defaultExports[0].declaration.callee.name === 'codegenNativeComponent';
|
||||
|
||||
const typesExtendingTurboModule = Object.keys(types)
|
||||
.map(typeName => types[typeName])
|
||||
.filter(
|
||||
type =>
|
||||
type.extends &&
|
||||
type.extends[0] &&
|
||||
type.extends[0].id.name === 'TurboModule',
|
||||
);
|
||||
|
||||
if (typesExtendingTurboModule.length > 1) {
|
||||
throw new Error(
|
||||
'Found two types extending "TurboModule" is one file. Split them into separated files.',
|
||||
);
|
||||
}
|
||||
if (defaultExports[0].declaration && defaultExports[0].declaration.callee) {
|
||||
const statement = defaultExports[0].declaration.callee;
|
||||
if (statement.name === 'codegenNativeComponent') {
|
||||
return 'component';
|
||||
}
|
||||
if (statement.object && statement.object.name === 'TurboModuleRegistry') {
|
||||
return 'module';
|
||||
}
|
||||
|
||||
const isModule = typesExtendingTurboModule.length === 1;
|
||||
|
||||
if (isModule && isComponent) {
|
||||
throw new Error(
|
||||
'Found type extending "TurboModule" and exported "codegenNativeComponent" declaration in one file. Split them into separated files.',
|
||||
);
|
||||
}
|
||||
|
||||
if (isModule) {
|
||||
return 'module';
|
||||
} else if (isComponent) {
|
||||
return 'component';
|
||||
} else {
|
||||
throw new Error(
|
||||
`Default export for module specified incorrectly. It should containts
|
||||
either type extending "TurboModule" or "codegenNativeComponent".`,
|
||||
);
|
||||
}
|
||||
throw new Error(
|
||||
`Default export for module specified incorrectly. It should containts
|
||||
either "TurboModuleRegistry.getEnforcing" or "codegenNativeComponent".`,
|
||||
);
|
||||
}
|
||||
|
||||
function buildSchema(contents: string): ?SchemaType {
|
||||
function buildSchema(contents: string, filename: ?string): ?SchemaType {
|
||||
const ast = flowParser.parse(contents);
|
||||
|
||||
const configType = getConfigType(ast);
|
||||
|
||||
const types = getTypes(ast);
|
||||
|
||||
const configType = getConfigType(ast, types);
|
||||
|
||||
if (configType === 'component') {
|
||||
return buildComponentSchema(processComponent(ast, types));
|
||||
} else {
|
||||
return buildModuleSchema(processModule(ast, types));
|
||||
if (filename === undefined || filename === null) {
|
||||
throw new Error('Filepath expected while parasing a module');
|
||||
}
|
||||
const moduleName = path.basename(filename).slice(6, -3);
|
||||
return buildModuleSchema(processModule(types), moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
function parseFile(filename: string): ?SchemaType {
|
||||
const contents = fs.readFileSync(filename, 'utf8');
|
||||
|
||||
return buildSchema(contents);
|
||||
return buildSchema(contents, filename);
|
||||
}
|
||||
|
||||
function parseModuleFixture(filename: string): ?SchemaType {
|
||||
const contents = fs.readFileSync(filename, 'utf8');
|
||||
|
||||
return buildSchema(contents, 'path/NativeSampleTurboModule.js');
|
||||
}
|
||||
|
||||
function parseString(contents: string): ?SchemaType {
|
||||
|
@ -83,5 +117,6 @@ function parseString(contents: string): ?SchemaType {
|
|||
|
||||
module.exports = {
|
||||
parseFile,
|
||||
parseModuleFixture,
|
||||
parseString,
|
||||
};
|
||||
|
|
|
@ -159,30 +159,6 @@ export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
|||
|
||||
`;
|
||||
|
||||
const INCORRECT_NATIVE_MODULES = `
|
||||
/**
|
||||
* 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';
|
||||
|
||||
import type {TurboModule} from '../RCTExport';
|
||||
import * as TurboModuleRegistry from '../TurboModuleRegistry';
|
||||
|
||||
export interface SpecWithoutTypo extends TurboModule {
|
||||
// no methods
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<SpecWithTypo>('SampleTurboModule');
|
||||
|
||||
`;
|
||||
|
||||
const NATIVE_MODULE_NULLABLE_BOOLEAN = `
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
|
@ -251,6 +227,33 @@ import * as TurboModuleRegistry from '../TurboModuleRegistry';
|
|||
export default TurboModuleRegistry.getEnforcing<Spec1>('SampleTurboModule1');
|
||||
export default TurboModuleRegistry.getEnforcing<Spec2>('SampleTurboModule2');
|
||||
|
||||
`;
|
||||
|
||||
const TWO_NATIVE_EXTENDING_TURBO_MODULE = `
|
||||
/**
|
||||
* 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';
|
||||
|
||||
import type {TurboModule} from '../RCTExport';
|
||||
import * as TurboModuleRegistry from '../TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+getSth(a : ?number) => void
|
||||
}
|
||||
|
||||
export interface Spec2 extends TurboModule {
|
||||
+getSth(a : ?number) => void
|
||||
}
|
||||
|
||||
|
||||
`;
|
||||
|
||||
module.exports = {
|
||||
|
@ -263,5 +266,5 @@ module.exports = {
|
|||
NATIVE_MODULES_WITH_NOT_EXISTING_TYPE_AS_PARAM,
|
||||
NATIVE_MODULES_WITH_NOT_EXISTING_TYPE_AS_RETURN,
|
||||
NATIVE_MODULES_WITH_NOT_ONLY_METHODS,
|
||||
INCORRECT_NATIVE_MODULES,
|
||||
TWO_NATIVE_EXTENDING_TURBO_MODULE,
|
||||
};
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message INCORRECT_NATIVE_MODULES 1`] = `"Interface properties for \\"SpecWithTypo has been specified incorrectly.\\""`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULE_NULLABLE_BOOLEAN 1`] = `"Booleans and numbers cannot be nullable for param \\"a in method \\"getSth\\"."`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULE_NULLABLE_NUMBER 1`] = `"Booleans and numbers cannot be nullable for param \\"a in method \\"getSth\\"."`;
|
||||
|
@ -18,12 +16,17 @@ exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULES_WITH_NOT
|
|||
|
||||
exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULES_WITH_PROMISE_WITHOUT_TYPE 1`] = `"Unsupported return promise type for getBool: expected to find annotation for type of promise content"`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message TWO_NATIVE_MODULES_EXPORTED_WITH_DEFAULT 1`] = `"File should contain only one default export."`;
|
||||
exports[`RN Codegen Flow Parser Fails with error message TWO_NATIVE_EXTENDING_TURBO_MODULE 1`] = `"Found two types extending \\"TurboModule\\" is one file. Split them into separated files."`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message TWO_NATIVE_MODULES_EXPORTED_WITH_DEFAULT 1`] = `
|
||||
"Default export for module specified incorrectly. It should containts
|
||||
either type extending \\"TurboModule\\" or \\"codegenNativeComponent\\"."
|
||||
`;
|
||||
|
||||
exports[`RN Codegen Flow Parser can generate fixture EMPTY_NATIVE_MODULE 1`] = `
|
||||
Object {
|
||||
"modules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"NativeSampleTurboModule": Object {
|
||||
"nativeModules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"properties": Array [],
|
||||
|
@ -37,7 +40,7 @@ Object {
|
|||
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ARRAY_WITH_ALIAS 1`] = `
|
||||
Object {
|
||||
"modules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"NativeSampleTurboModule": Object {
|
||||
"nativeModules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"properties": Array [
|
||||
|
@ -77,7 +80,7 @@ Object {
|
|||
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_BASIC_ARRAY 1`] = `
|
||||
Object {
|
||||
"modules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"NativeSampleTurboModule": Object {
|
||||
"nativeModules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"properties": Array [
|
||||
|
@ -117,7 +120,7 @@ Object {
|
|||
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_BASIC_PARAM_TYPES 1`] = `
|
||||
Object {
|
||||
"modules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"NativeSampleTurboModule": Object {
|
||||
"nativeModules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"properties": Array [
|
||||
|
@ -189,7 +192,7 @@ Object {
|
|||
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_CALLBACK 1`] = `
|
||||
Object {
|
||||
"modules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"NativeSampleTurboModule": Object {
|
||||
"nativeModules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"properties": Array [
|
||||
|
@ -248,7 +251,7 @@ Object {
|
|||
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ARRAY 1`] = `
|
||||
Object {
|
||||
"modules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"NativeSampleTurboModule": Object {
|
||||
"nativeModules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"properties": Array [
|
||||
|
@ -306,7 +309,7 @@ Object {
|
|||
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_OBJECTS 1`] = `
|
||||
Object {
|
||||
"modules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"NativeSampleTurboModule": Object {
|
||||
"nativeModules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"properties": Array [
|
||||
|
@ -453,7 +456,7 @@ Object {
|
|||
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_NULLABLE_PARAM 1`] = `
|
||||
Object {
|
||||
"modules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"NativeSampleTurboModule": Object {
|
||||
"nativeModules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"properties": Array [
|
||||
|
@ -487,7 +490,7 @@ Object {
|
|||
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PROMISE 1`] = `
|
||||
Object {
|
||||
"modules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"NativeSampleTurboModule": Object {
|
||||
"nativeModules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"properties": Array [
|
||||
|
@ -530,7 +533,7 @@ Object {
|
|||
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_SIMPLE_OBJECT 1`] = `
|
||||
Object {
|
||||
"modules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"NativeSampleTurboModule": Object {
|
||||
"nativeModules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"properties": Array [
|
||||
|
@ -564,7 +567,7 @@ Object {
|
|||
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_WITH_ALIASES 1`] = `
|
||||
Object {
|
||||
"modules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"NativeSampleTurboModule": Object {
|
||||
"nativeModules": Object {
|
||||
"SampleTurboModule": Object {
|
||||
"properties": Array [
|
||||
|
|
|
@ -23,7 +23,7 @@ describe('RN Codegen Flow Parser', () => {
|
|||
.sort()
|
||||
.forEach(fixtureName => {
|
||||
it(`can generate fixture ${fixtureName}`, () => {
|
||||
expect(FlowParser.parseFile(fixtureName)).toMatchSnapshot();
|
||||
expect(FlowParser.parseModuleFixture(fixtureName)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -32,7 +32,7 @@ describe('RN Codegen Flow Parser', () => {
|
|||
.forEach(fixtureName => {
|
||||
it(`Fails with error message ${fixtureName}`, () => {
|
||||
expect(() => {
|
||||
FlowParser.parseFile(fixtureName);
|
||||
FlowParser.parseModuleFixture(fixtureName);
|
||||
}).toThrowErrorMatchingSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,37 +18,28 @@ function getModuleProperties(types, interfaceName) {
|
|||
return types[interfaceName].body.properties;
|
||||
}
|
||||
throw new Error(
|
||||
`Interface properties for "${interfaceName} has been specified incorrectly."`,
|
||||
`Interface properties for "${interfaceName}" has been specified incorrectly.`,
|
||||
);
|
||||
}
|
||||
|
||||
function findModuleConfig(
|
||||
ast,
|
||||
): $ReadOnly<{|moduleName: string, interfaceName: string|}> {
|
||||
const defaultExport = ast.body.filter(
|
||||
node => node.type === 'ExportDefaultDeclaration',
|
||||
)[0];
|
||||
try {
|
||||
const interfaceName =
|
||||
defaultExport.declaration.typeArguments.params[0].id.name;
|
||||
|
||||
const moduleName = defaultExport.declaration.arguments[0].value;
|
||||
return {interfaceName, moduleName};
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Default export for module specified incorrectly. It should containts
|
||||
either "TurboModuleRegistry.getEnforcing" or "codegenNativeComponent".`,
|
||||
);
|
||||
}
|
||||
function findInterfaceName(types) {
|
||||
return Object.keys(types)
|
||||
.map(typeName => types[typeName])
|
||||
.filter(
|
||||
type =>
|
||||
type.extends &&
|
||||
type.extends[0] &&
|
||||
type.extends[0].id.name === 'TurboModule',
|
||||
)[0].id.name;
|
||||
}
|
||||
|
||||
// $FlowFixMe there's no flowtype for AST
|
||||
function processModule(ast, types): NativeModuleSchemaBuilderConfig {
|
||||
const {interfaceName, moduleName} = findModuleConfig(ast);
|
||||
function processModule(types): NativeModuleSchemaBuilderConfig {
|
||||
const interfaceName = findInterfaceName(types);
|
||||
|
||||
const moduleProperties = getModuleProperties(types, interfaceName);
|
||||
const properties = getMethods(moduleProperties, types);
|
||||
return {properties, filename: moduleName, moduleName};
|
||||
return {properties};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
|
|
@ -13,19 +13,16 @@
|
|||
import type {SchemaType, MethodTypeShape} from '../../../CodegenSchema.js';
|
||||
|
||||
export type NativeModuleSchemaBuilderConfig = $ReadOnly<{|
|
||||
filename: string,
|
||||
moduleName: string,
|
||||
properties: $ReadOnlyArray<MethodTypeShape>,
|
||||
|}>;
|
||||
|
||||
function buildModuleSchema({
|
||||
filename,
|
||||
moduleName,
|
||||
properties,
|
||||
}: NativeModuleSchemaBuilderConfig): SchemaType {
|
||||
function buildModuleSchema(
|
||||
{properties}: NativeModuleSchemaBuilderConfig,
|
||||
moduleName: string,
|
||||
): SchemaType {
|
||||
return {
|
||||
modules: {
|
||||
[filename]: {
|
||||
[`Native${moduleName}`]: {
|
||||
nativeModules: {
|
||||
[moduleName]: {
|
||||
properties,
|
||||
|
|
Загрузка…
Ссылка в новой задаче