Extract the parseFile function in the typescript and flow parsers (#35318)
Summary: This PR aims to extract the parseFile function in the typescript and flow parsers. This is to solve the problem described [here](https://github.com/facebook/react-native/pull/35158#issuecomment-1298330753) and help with the work done in https://github.com/facebook/react-native/issues/34872. ## Changelog <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> [Internal] [Changed] - Extract the parseFile function in the typescript and flow parsers Pull Request resolved: https://github.com/facebook/react-native/pull/35318 Test Plan: yarn flow: <img width="496" alt="image" src="https://user-images.githubusercontent.com/40902940/206518024-83084c3d-ab0d-4a04-810a-d40270add4b0.png"> yarn lint: <img width="495" alt="image" src="https://user-images.githubusercontent.com/40902940/206518076-9e07eafe-db61-4c6e-8aaa-f92f190cf4f3.png"> yarn test: <img width="389" alt="image" src="https://user-images.githubusercontent.com/40902940/206518118-5633b28c-b79b-4421-80f7-de1e03fb8ff2.png"> Reviewed By: cortinico Differential Revision: D41248581 Pulled By: cipolleschi fbshipit-source-id: f5b878a28a7de612fcdd1528f064b44f668503af
This commit is contained in:
Родитель
234486068e
Коммит
3f2691cf84
|
@ -23,9 +23,10 @@ const ERRORS = {
|
|||
|
||||
let RNModuleParser;
|
||||
let RNParserUtils;
|
||||
let RNFlowParser;
|
||||
|
||||
function requireModuleParser() {
|
||||
if (RNModuleParser == null || RNParserUtils == null) {
|
||||
if (RNModuleParser == null || RNParserUtils == null || RNFlowParser == null) {
|
||||
// If using this externally, we leverage @react-native/codegen as published form
|
||||
if (!PACKAGE_USAGE) {
|
||||
const config = {
|
||||
|
@ -36,6 +37,7 @@ function requireModuleParser() {
|
|||
withBabelRegister(config, () => {
|
||||
RNModuleParser = require('@react-native/codegen/src/parsers/flow/modules');
|
||||
RNParserUtils = require('@react-native/codegen/src/parsers/utils');
|
||||
RNFlowParser = require('@react-native/codegen/src/parsers/flow/parser');
|
||||
});
|
||||
} else {
|
||||
const config = {
|
||||
|
@ -46,6 +48,7 @@ function requireModuleParser() {
|
|||
withBabelRegister(config, () => {
|
||||
RNModuleParser = require('@react-native/codegen/lib/parsers/flow/modules');
|
||||
RNParserUtils = require('@react-native/codegen/lib/parsers/flow/utils');
|
||||
RNFlowParser = require('@react-native/codegen/lib/parsers/flow/parser');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +56,7 @@ function requireModuleParser() {
|
|||
return {
|
||||
buildModuleSchema: RNModuleParser.buildModuleSchema,
|
||||
createParserErrorCapturer: RNParserUtils.createParserErrorCapturer,
|
||||
parser: new RNFlowParser.FlowParser(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -127,7 +131,7 @@ function rule(context) {
|
|||
});
|
||||
}
|
||||
|
||||
const {buildModuleSchema, createParserErrorCapturer} =
|
||||
const {buildModuleSchema, createParserErrorCapturer, parser} =
|
||||
requireModuleParser();
|
||||
const flowParser = require('flow-parser');
|
||||
|
||||
|
@ -137,7 +141,7 @@ function rule(context) {
|
|||
const ast = flowParser.parse(sourceCode, {enums: true});
|
||||
|
||||
tryParse(() => {
|
||||
buildModuleSchema(hasteModuleName, ast, tryParse);
|
||||
buildModuleSchema(hasteModuleName, ast, tryParse, parser);
|
||||
});
|
||||
|
||||
parsingErrors.forEach(error => {
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const {parseFile} = require('../../../src/parsers/utils');
|
||||
const FlowParser = require('../../../src/parsers/flow');
|
||||
const {FlowParser} = require('../../../src/parsers/flow/parser');
|
||||
const generator = require('../../../src/generators/components/GenerateComponentDescriptorH');
|
||||
const fs = require('fs');
|
||||
|
||||
|
@ -20,13 +19,12 @@ const FIXTURE_DIR = `${__dirname}/../../__test_fixtures__/components`;
|
|||
|
||||
const fixtures = fs.readdirSync(FIXTURE_DIR);
|
||||
|
||||
const parser = new FlowParser();
|
||||
|
||||
fixtures.forEach(fixture => {
|
||||
it(`GenerateComponentDescriptorH can generate for '${fixture}'`, () => {
|
||||
const libName = 'RNCodegenModuleFixtures';
|
||||
const schema = parseFile(
|
||||
`${FIXTURE_DIR}/${fixture}`,
|
||||
FlowParser.buildSchema,
|
||||
);
|
||||
const schema = parser.parseFile(`${FIXTURE_DIR}/${fixture}`);
|
||||
const output = generator.generate(libName, schema);
|
||||
expect(Object.fromEntries(output)).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const {parseFile} = require('../../../src/parsers/utils');
|
||||
const FlowParser = require('../../../src/parsers/flow');
|
||||
const {FlowParser} = require('../../../src/parsers/flow/parser');
|
||||
const generator = require('../../../src/generators/components/GenerateComponentHObjCpp');
|
||||
const fs = require('fs');
|
||||
|
||||
|
@ -20,13 +19,12 @@ const FIXTURE_DIR = `${__dirname}/../../__test_fixtures__/components`;
|
|||
|
||||
const fixtures = fs.readdirSync(FIXTURE_DIR);
|
||||
|
||||
const parser = new FlowParser();
|
||||
|
||||
fixtures.forEach(fixture => {
|
||||
it(`GenerateComponentHObjCpp can generate for '${fixture}'`, () => {
|
||||
const libName = 'RNCodegenModuleFixtures';
|
||||
const schema = parseFile(
|
||||
`${FIXTURE_DIR}/${fixture}`,
|
||||
FlowParser.buildSchema,
|
||||
);
|
||||
const schema = parser.parseFile(`${FIXTURE_DIR}/${fixture}`);
|
||||
const output = generator.generate(libName, schema);
|
||||
expect(Object.fromEntries(output)).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const {parseFile} = require('../../../src/parsers/utils');
|
||||
const FlowParser = require('../../../src/parsers/flow');
|
||||
const {FlowParser} = require('../../../src/parsers/flow/parser');
|
||||
const generator = require('../../../src/generators/components/GenerateEventEmitterCpp');
|
||||
const fs = require('fs');
|
||||
|
||||
|
@ -20,13 +19,12 @@ const FIXTURE_DIR = `${__dirname}/../../__test_fixtures__/components`;
|
|||
|
||||
const fixtures = fs.readdirSync(FIXTURE_DIR);
|
||||
|
||||
const parser = new FlowParser();
|
||||
|
||||
fixtures.forEach(fixture => {
|
||||
it(`GenerateEventEmitterCpp can generate for '${fixture}'`, () => {
|
||||
const libName = 'RNCodegenModuleFixtures';
|
||||
const schema = parseFile(
|
||||
`${FIXTURE_DIR}/${fixture}`,
|
||||
FlowParser.buildSchema,
|
||||
);
|
||||
const schema = parser.parseFile(`${FIXTURE_DIR}/${fixture}`);
|
||||
const output = generator.generate(libName, schema);
|
||||
expect(Object.fromEntries(output)).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const {parseFile} = require('../../../src/parsers/utils');
|
||||
const FlowParser = require('../../../src/parsers/flow');
|
||||
const {FlowParser} = require('../../../src/parsers/flow/parser');
|
||||
const generator = require('../../../src/generators/components/GenerateEventEmitterH');
|
||||
const fs = require('fs');
|
||||
|
||||
|
@ -20,13 +19,12 @@ const FIXTURE_DIR = `${__dirname}/../../__test_fixtures__/components`;
|
|||
|
||||
const fixtures = fs.readdirSync(FIXTURE_DIR);
|
||||
|
||||
const parser = new FlowParser();
|
||||
|
||||
fixtures.forEach(fixture => {
|
||||
it(`GenerateEventEmitterH can generate for '${fixture}'`, () => {
|
||||
const libName = 'RNCodegenModuleFixtures';
|
||||
const schema = parseFile(
|
||||
`${FIXTURE_DIR}/${fixture}`,
|
||||
FlowParser.buildSchema,
|
||||
);
|
||||
const schema = parser.parseFile(`${FIXTURE_DIR}/${fixture}`);
|
||||
const output = generator.generate(libName, schema);
|
||||
expect(Object.fromEntries(output)).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const {parseFile} = require('../../../src/parsers/utils');
|
||||
const FlowParser = require('../../../src/parsers/flow');
|
||||
const {FlowParser} = require('../../../src/parsers/flow/parser');
|
||||
const generator = require('../../../src/generators/components/GeneratePropsCpp');
|
||||
const fs = require('fs');
|
||||
|
||||
|
@ -20,13 +19,12 @@ const FIXTURE_DIR = `${__dirname}/../../__test_fixtures__/components`;
|
|||
|
||||
const fixtures = fs.readdirSync(FIXTURE_DIR);
|
||||
|
||||
const parser = new FlowParser();
|
||||
|
||||
fixtures.forEach(fixture => {
|
||||
it(`GeneratePropsCpp can generate for '${fixture}'`, () => {
|
||||
const libName = 'RNCodegenModuleFixtures';
|
||||
const schema = parseFile(
|
||||
`${FIXTURE_DIR}/${fixture}`,
|
||||
FlowParser.buildSchema,
|
||||
);
|
||||
const schema = parser.parseFile(`${FIXTURE_DIR}/${fixture}`);
|
||||
const output = generator.generate(libName, schema);
|
||||
expect(Object.fromEntries(output)).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const {parseFile} = require('../../../src/parsers/utils');
|
||||
const FlowParser = require('../../../src/parsers/flow');
|
||||
const {FlowParser} = require('../../../src/parsers/flow/parser');
|
||||
const generator = require('../../../src/generators/components/GeneratePropsH');
|
||||
const fs = require('fs');
|
||||
|
||||
|
@ -20,13 +19,12 @@ const FIXTURE_DIR = `${__dirname}/../../__test_fixtures__/components`;
|
|||
|
||||
const fixtures = fs.readdirSync(FIXTURE_DIR);
|
||||
|
||||
const parser = new FlowParser();
|
||||
|
||||
fixtures.forEach(fixture => {
|
||||
it(`GeneratePropsH can generate for '${fixture}'`, () => {
|
||||
const libName = 'RNCodegenModuleFixtures';
|
||||
const schema = parseFile(
|
||||
`${FIXTURE_DIR}/${fixture}`,
|
||||
FlowParser.buildSchema,
|
||||
);
|
||||
const schema = parser.parseFile(`${FIXTURE_DIR}/${fixture}`);
|
||||
const output = generator.generate(libName, schema);
|
||||
expect(Object.fromEntries(output)).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const {parseFile} = require('../../../src/parsers/utils');
|
||||
const FlowParser = require('../../../src/parsers/flow');
|
||||
const {FlowParser} = require('../../../src/parsers/flow/parser');
|
||||
const generator = require('../../../src/generators/components/GeneratePropsJavaDelegate');
|
||||
const fs = require('fs');
|
||||
|
||||
|
@ -20,13 +19,12 @@ const FIXTURE_DIR = `${__dirname}/../../__test_fixtures__/components`;
|
|||
|
||||
const fixtures = fs.readdirSync(FIXTURE_DIR);
|
||||
|
||||
const parser = new FlowParser();
|
||||
|
||||
fixtures.forEach(fixture => {
|
||||
it(`GeneratePropsJavaDelegate can generate for '${fixture}'`, () => {
|
||||
const libName = 'RNCodegenModuleFixtures';
|
||||
const schema = parseFile(
|
||||
`${FIXTURE_DIR}/${fixture}`,
|
||||
FlowParser.buildSchema,
|
||||
);
|
||||
const schema = parser.parseFile(`${FIXTURE_DIR}/${fixture}`);
|
||||
const output = generator.generate(libName, schema);
|
||||
expect(Object.fromEntries(output)).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -11,21 +11,19 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const {parseFile} = require('../../../src/parsers/utils');
|
||||
const FlowParser = require('../../../src/parsers/flow');
|
||||
const {FlowParser} = require('../../../src/parsers/flow/parser');
|
||||
const generator = require('../../../src/generators/components/GeneratePropsJavaInterface');
|
||||
const fs = require('fs');
|
||||
|
||||
const FIXTURE_DIR = `${__dirname}/../../__test_fixtures__/components`;
|
||||
const fixtures = fs.readdirSync(FIXTURE_DIR);
|
||||
|
||||
const parser = new FlowParser();
|
||||
|
||||
fixtures.forEach(fixture => {
|
||||
it(`GeneratePropsJavaInterface can generate for '${fixture}'`, () => {
|
||||
const libName = 'RNCodegenModuleFixtures';
|
||||
const schema = parseFile(
|
||||
`${FIXTURE_DIR}/${fixture}`,
|
||||
FlowParser.buildSchema,
|
||||
);
|
||||
const schema = parser.parseFile(`${FIXTURE_DIR}/${fixture}`);
|
||||
const output = generator.generate(libName, schema, undefined, false);
|
||||
expect(Object.fromEntries(output)).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -11,21 +11,19 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const {parseFile} = require('../../../src/parsers/utils');
|
||||
const FlowParser = require('../../../src/parsers/flow');
|
||||
const {FlowParser} = require('../../../src/parsers/flow/parser');
|
||||
const generator = require('../../../src/generators/components/GenerateShadowNodeCpp');
|
||||
const fs = require('fs');
|
||||
|
||||
const FIXTURE_DIR = `${__dirname}/../../__test_fixtures__/components`;
|
||||
const fixtures = fs.readdirSync(FIXTURE_DIR);
|
||||
|
||||
const parser = new FlowParser();
|
||||
|
||||
fixtures.forEach(fixture => {
|
||||
it(`GenerateShadowNodeCpp can generate for '${fixture}'`, () => {
|
||||
const libName = 'RNCodegenModuleFixtures';
|
||||
const schema = parseFile(
|
||||
`${FIXTURE_DIR}/${fixture}`,
|
||||
FlowParser.buildSchema,
|
||||
);
|
||||
const schema = parser.parseFile(`${FIXTURE_DIR}/${fixture}`);
|
||||
const output = generator.generate(libName, schema, undefined, false);
|
||||
expect(Object.fromEntries(output)).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -11,21 +11,19 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const {parseFile} = require('../../../src/parsers/utils');
|
||||
const FlowParser = require('../../../src/parsers/flow');
|
||||
const {FlowParser} = require('../../../src/parsers/flow/parser');
|
||||
const generator = require('../../../src/generators/components/GenerateShadowNodeH');
|
||||
const fs = require('fs');
|
||||
|
||||
const FIXTURE_DIR = `${__dirname}/../../__test_fixtures__/components`;
|
||||
const fixtures = fs.readdirSync(FIXTURE_DIR);
|
||||
|
||||
const parser = new FlowParser();
|
||||
|
||||
fixtures.forEach(fixture => {
|
||||
it(`GenerateShadowNodeH can generate for '${fixture}'`, () => {
|
||||
const libName = 'RNCodegenModuleFixtures';
|
||||
const schema = parseFile(
|
||||
`${FIXTURE_DIR}/${fixture}`,
|
||||
FlowParser.buildSchema,
|
||||
);
|
||||
const schema = parser.parseFile(`${FIXTURE_DIR}/${fixture}`);
|
||||
const output = generator.generate(libName, schema, undefined, false);
|
||||
expect(Object.fromEntries(output)).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const {parseFile} = require('../../../src/parsers/utils');
|
||||
const FlowParser = require('../../../src/parsers/flow');
|
||||
const {FlowParser} = require('../../../src/parsers/flow/parser');
|
||||
const generator = require('../../../src/generators/components/GenerateViewConfigJs');
|
||||
const fs = require('fs');
|
||||
|
||||
|
@ -20,13 +19,12 @@ const FIXTURE_DIR = `${__dirname}/../../__test_fixtures__/components`;
|
|||
|
||||
const fixtures = fs.readdirSync(FIXTURE_DIR);
|
||||
|
||||
const parser = new FlowParser();
|
||||
|
||||
fixtures.forEach(fixture => {
|
||||
it(`GenerateViewConfigJs can generate for '${fixture}'`, () => {
|
||||
const libName = 'RNCodegenModuleFixtures';
|
||||
const schema = parseFile(
|
||||
`${FIXTURE_DIR}/${fixture}`,
|
||||
FlowParser.buildSchema,
|
||||
);
|
||||
const schema = parser.parseFile(`${FIXTURE_DIR}/${fixture}`);
|
||||
const output = generator.generate(libName, schema);
|
||||
expect(output).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const {parseFile} = require('../../../src/parsers/utils');
|
||||
const FlowParser = require('../../../src/parsers/flow');
|
||||
const {FlowParser} = require('../../../src/parsers/flow/parser');
|
||||
const generator = require('../../../src/generators/modules/GenerateModuleObjCpp');
|
||||
const fs = require('fs');
|
||||
|
||||
|
@ -20,14 +19,13 @@ import type {SchemaType} from '../../../src/CodegenSchema';
|
|||
|
||||
const FIXTURE_DIR = `${__dirname}/../../__test_fixtures__/modules`;
|
||||
|
||||
const parser = new FlowParser();
|
||||
|
||||
function getModules(): SchemaType {
|
||||
const filenames: Array<string> = fs.readdirSync(FIXTURE_DIR);
|
||||
return filenames.reduce<SchemaType>(
|
||||
(accumulator, file) => {
|
||||
const schema = parseFile(
|
||||
`${FIXTURE_DIR}/${file}`,
|
||||
FlowParser.buildSchema,
|
||||
);
|
||||
const schema = parser.parseFile(`${FIXTURE_DIR}/${file}`);
|
||||
return {
|
||||
modules: {
|
||||
...accumulator.modules,
|
||||
|
|
|
@ -11,12 +11,14 @@
|
|||
'use strict';
|
||||
import type {SchemaType} from '../../CodegenSchema.js';
|
||||
|
||||
const {parseFile} = require('../../parsers/utils');
|
||||
const FlowParser = require('../../parsers/flow');
|
||||
const TypeScriptParser = require('../../parsers/typescript');
|
||||
const {FlowParser} = require('../../parsers/flow/parser');
|
||||
const {TypeScriptParser} = require('../../parsers/typescript/parser');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const flowParser = new FlowParser();
|
||||
const typescriptParser = new TypeScriptParser();
|
||||
|
||||
function combineSchemas(files: Array<string>): SchemaType {
|
||||
return files.reduce(
|
||||
(merged, filename) => {
|
||||
|
@ -30,10 +32,9 @@ function combineSchemas(files: Array<string>): SchemaType {
|
|||
const isTypeScript =
|
||||
path.extname(filename) === '.ts' || path.extname(filename) === '.tsx';
|
||||
|
||||
const schema = parseFile(
|
||||
filename,
|
||||
isTypeScript ? TypeScriptParser.buildSchema : FlowParser.buildSchema,
|
||||
);
|
||||
const parser = isTypeScript ? typescriptParser : flowParser;
|
||||
|
||||
const schema = parser.parseFile(filename);
|
||||
|
||||
if (schema && schema.modules) {
|
||||
merged.modules = {...merged.modules, ...schema.modules};
|
||||
|
|
|
@ -11,26 +11,20 @@
|
|||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const {parseFile} = require('../../parsers/utils');
|
||||
const FlowParser = require('../../parsers/flow');
|
||||
const TypeScriptParser = require('../../parsers/typescript');
|
||||
const {FlowParser} = require('../../parsers/flow/parser');
|
||||
const {TypeScriptParser} = require('../../parsers/typescript/parser');
|
||||
|
||||
const flowParser = new FlowParser();
|
||||
const typescriptParser = new TypeScriptParser();
|
||||
|
||||
function parseFiles(files: Array<string>) {
|
||||
files.forEach(filename => {
|
||||
const isTypeScript =
|
||||
path.extname(filename) === '.ts' || path.extname(filename) === '.tsx';
|
||||
|
||||
console.log(
|
||||
filename,
|
||||
JSON.stringify(
|
||||
parseFile(
|
||||
filename,
|
||||
isTypeScript ? TypeScriptParser.buildSchema : FlowParser.buildSchema,
|
||||
),
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
const parser = isTypeScript ? typescriptParser : flowParser;
|
||||
|
||||
console.log(filename, JSON.stringify(parser.parseFile(filename), null, 2));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const {MockedParser} = require('../parserMock');
|
||||
|
||||
const {
|
||||
extractNativeModuleName,
|
||||
createParserErrorCapturer,
|
||||
|
@ -297,6 +299,8 @@ describe('visit', () => {
|
|||
});
|
||||
|
||||
describe('buildSchemaFromConfigType', () => {
|
||||
const parser = new MockedParser();
|
||||
|
||||
const astMock = {
|
||||
type: 'Program',
|
||||
loc: {
|
||||
|
@ -332,7 +336,7 @@ describe('buildSchemaFromConfigType', () => {
|
|||
require('../parsers-commons'),
|
||||
'wrapModuleSchema',
|
||||
);
|
||||
const buildModuleSchemaMock = jest.fn((_0, _1, _2) => moduleSchemaMock);
|
||||
const buildModuleSchemaMock = jest.fn((_0, _1, _2, _3) => moduleSchemaMock);
|
||||
|
||||
const buildSchemaFromConfigTypeHelper = (
|
||||
configType: 'module' | 'component' | 'none',
|
||||
|
@ -345,6 +349,7 @@ describe('buildSchemaFromConfigType', () => {
|
|||
wrapComponentSchemaMock,
|
||||
buildComponentSchemaMock,
|
||||
buildModuleSchemaMock,
|
||||
parser,
|
||||
);
|
||||
|
||||
describe('when configType is none', () => {
|
||||
|
@ -426,6 +431,7 @@ describe('buildSchemaFromConfigType', () => {
|
|||
'filename',
|
||||
astMock,
|
||||
expect.any(Function),
|
||||
parser,
|
||||
);
|
||||
expect(wrapModuleSchemaMock).toHaveBeenCalledTimes(1);
|
||||
expect(wrapModuleSchemaMock).toHaveBeenCalledWith(
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {SchemaType} from '../../CodegenSchema';
|
||||
import type {Parser} from '../parser';
|
||||
|
||||
// $FlowFixMe[untyped-import] there's no flowtype flow-parser
|
||||
const flowParser = require('flow-parser');
|
||||
const {
|
||||
getConfigType,
|
||||
buildSchemaFromConfigType,
|
||||
isModuleRegistryCall,
|
||||
} = require('../utils');
|
||||
const {buildComponentSchema} = require('./components');
|
||||
const {wrapComponentSchema} = require('./components/schema');
|
||||
const {buildModuleSchema} = require('./modules');
|
||||
|
||||
function Visitor(infoMap: {isComponent: boolean, isModule: boolean}) {
|
||||
return {
|
||||
CallExpression(node: $FlowFixMe) {
|
||||
if (
|
||||
node.callee.type === 'Identifier' &&
|
||||
node.callee.name === 'codegenNativeComponent'
|
||||
) {
|
||||
infoMap.isComponent = true;
|
||||
}
|
||||
|
||||
if (isModuleRegistryCall(node)) {
|
||||
infoMap.isModule = true;
|
||||
}
|
||||
},
|
||||
InterfaceExtends(node: $FlowFixMe) {
|
||||
if (node.id.name === 'TurboModule') {
|
||||
infoMap.isModule = true;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function buildSchema(
|
||||
contents: string,
|
||||
filename: ?string,
|
||||
parser: Parser,
|
||||
): SchemaType {
|
||||
// Early return for non-Spec JavaScript files
|
||||
if (
|
||||
!contents.includes('codegenNativeComponent') &&
|
||||
!contents.includes('TurboModule')
|
||||
) {
|
||||
return {modules: {}};
|
||||
}
|
||||
|
||||
const ast = flowParser.parse(contents, {enums: true});
|
||||
const configType = getConfigType(ast, Visitor);
|
||||
|
||||
return buildSchemaFromConfigType(
|
||||
configType,
|
||||
filename,
|
||||
ast,
|
||||
wrapComponentSchema,
|
||||
buildComponentSchema,
|
||||
buildModuleSchema,
|
||||
parser,
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
buildSchema,
|
||||
};
|
|
@ -11,8 +11,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const FlowParser = require('../../index.js');
|
||||
const {parseFile} = require('../../../utils.js');
|
||||
const {FlowParser} = require('../../parser');
|
||||
const fixtures = require('../__test_fixtures__/fixtures.js');
|
||||
const failureFixtures = require('../__test_fixtures__/failures.js');
|
||||
jest.mock('fs', () => ({
|
||||
|
@ -26,12 +25,14 @@ jest.mock('fs', () => ({
|
|||
},
|
||||
}));
|
||||
|
||||
const parser = new FlowParser();
|
||||
|
||||
describe('RN Codegen Flow Parser', () => {
|
||||
Object.keys(fixtures)
|
||||
.sort()
|
||||
.forEach(fixtureName => {
|
||||
it(`can generate fixture ${fixtureName}`, () => {
|
||||
const schema = parseFile(fixtureName, FlowParser.buildSchema);
|
||||
const schema = parser.parseFile(fixtureName);
|
||||
const serializedSchema = JSON.stringify(schema, null, 2).replace(
|
||||
/"/g,
|
||||
"'",
|
||||
|
@ -45,7 +46,7 @@ describe('RN Codegen Flow Parser', () => {
|
|||
.forEach(fixtureName => {
|
||||
it(`Fails with error message ${fixtureName}`, () => {
|
||||
expect(() => {
|
||||
parseFile(fixtureName, FlowParser.buildSchema);
|
||||
parser.parseFile(fixtureName);
|
||||
}).toThrowErrorMatchingSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
|
@ -18,6 +18,7 @@ import type {TypeDeclarationMap} from '../../utils';
|
|||
|
||||
const {getValueFromTypes} = require('../utils.js');
|
||||
|
||||
// $FlowFixMe[unclear-type] there's no flowtype for ASTs
|
||||
type EventTypeAST = Object;
|
||||
|
||||
function buildCommandSchema(property: EventTypeAST, types: TypeDeclarationMap) {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
|
@ -12,74 +12,23 @@
|
|||
|
||||
import type {SchemaType} from '../../CodegenSchema.js';
|
||||
|
||||
// $FlowFixMe[untyped-import] there's no flowtype flow-parser
|
||||
const flowParser = require('flow-parser');
|
||||
const fs = require('fs');
|
||||
const {
|
||||
buildSchemaFromConfigType,
|
||||
getConfigType,
|
||||
isModuleRegistryCall,
|
||||
} = require('../utils');
|
||||
const {buildComponentSchema} = require('./components');
|
||||
const {wrapComponentSchema} = require('./components/schema');
|
||||
const {buildModuleSchema} = require('./modules');
|
||||
const {buildSchema} = require('./buildSchema');
|
||||
const {FlowParser} = require('./parser');
|
||||
|
||||
function Visitor(infoMap: {isComponent: boolean, isModule: boolean}) {
|
||||
return {
|
||||
CallExpression(node: $FlowFixMe) {
|
||||
if (
|
||||
node.callee.type === 'Identifier' &&
|
||||
node.callee.name === 'codegenNativeComponent'
|
||||
) {
|
||||
infoMap.isComponent = true;
|
||||
}
|
||||
|
||||
if (isModuleRegistryCall(node)) {
|
||||
infoMap.isModule = true;
|
||||
}
|
||||
},
|
||||
InterfaceExtends(node: $FlowFixMe) {
|
||||
if (node.id.name === 'TurboModule') {
|
||||
infoMap.isModule = true;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function buildSchema(contents: string, filename: ?string): SchemaType {
|
||||
// Early return for non-Spec JavaScript files
|
||||
if (
|
||||
!contents.includes('codegenNativeComponent') &&
|
||||
!contents.includes('TurboModule')
|
||||
) {
|
||||
return {modules: {}};
|
||||
}
|
||||
|
||||
const ast = flowParser.parse(contents, {enums: true});
|
||||
const configType = getConfigType(ast, Visitor);
|
||||
|
||||
return buildSchemaFromConfigType(
|
||||
configType,
|
||||
filename,
|
||||
ast,
|
||||
wrapComponentSchema,
|
||||
buildComponentSchema,
|
||||
buildModuleSchema,
|
||||
);
|
||||
}
|
||||
const parser = new FlowParser();
|
||||
|
||||
function parseModuleFixture(filename: string): SchemaType {
|
||||
const contents = fs.readFileSync(filename, 'utf8');
|
||||
|
||||
return buildSchema(contents, 'path/NativeSampleTurboModule.js');
|
||||
return buildSchema(contents, 'path/NativeSampleTurboModule.js', parser);
|
||||
}
|
||||
|
||||
function parseString(contents: string, filename: ?string): SchemaType {
|
||||
return buildSchema(contents, filename);
|
||||
return buildSchema(contents, filename, parser);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
buildSchema,
|
||||
parseModuleFixture,
|
||||
parseString,
|
||||
};
|
||||
|
|
|
@ -19,6 +19,8 @@ import type {
|
|||
NativeModuleSchema,
|
||||
Nullable,
|
||||
} from '../../../CodegenSchema';
|
||||
|
||||
import type {Parser} from '../../parser';
|
||||
import type {ParserErrorCapturer, TypeDeclarationMap} from '../../utils';
|
||||
|
||||
const {visit, isModuleRegistryCall, verifyPlatforms} = require('../../utils');
|
||||
|
@ -67,10 +69,7 @@ const {
|
|||
throwIfMoreThanOneModuleInterfaceParserError,
|
||||
} = require('../../error-utils');
|
||||
|
||||
const {FlowParser} = require('../parser');
|
||||
|
||||
const language = 'Flow';
|
||||
const parser = new FlowParser();
|
||||
|
||||
function translateTypeAnnotation(
|
||||
hasteModuleName: string,
|
||||
|
@ -82,6 +81,7 @@ function translateTypeAnnotation(
|
|||
aliasMap: {...NativeModuleAliasMap},
|
||||
tryParse: ParserErrorCapturer,
|
||||
cxxOnly: boolean,
|
||||
parser: Parser,
|
||||
): Nullable<NativeModuleTypeAnnotation> {
|
||||
const {nullable, typeAnnotation, typeAliasResolutionStatus} =
|
||||
resolveTypeAnnotation(flowTypeAnnotation, types);
|
||||
|
@ -133,6 +133,7 @@ function translateTypeAnnotation(
|
|||
aliasMap,
|
||||
tryParse,
|
||||
cxxOnly,
|
||||
parser,
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -182,6 +183,7 @@ function translateTypeAnnotation(
|
|||
aliasMap,
|
||||
tryParse,
|
||||
cxxOnly,
|
||||
parser,
|
||||
);
|
||||
// no need to do further checking
|
||||
return emitObject(nullable);
|
||||
|
@ -244,7 +246,7 @@ function translateTypeAnnotation(
|
|||
tryParse,
|
||||
cxxOnly,
|
||||
translateTypeAnnotation,
|
||||
language,
|
||||
parser,
|
||||
);
|
||||
}
|
||||
case 'UnionTypeAnnotation': {
|
||||
|
@ -290,6 +292,7 @@ function buildModuleSchema(
|
|||
*/
|
||||
ast: $FlowFixMe,
|
||||
tryParse: ParserErrorCapturer,
|
||||
parser: Parser,
|
||||
): NativeModuleSchema {
|
||||
const types = getTypes(ast);
|
||||
const moduleSpecs = (Object.values(types): $ReadOnlyArray<$FlowFixMe>).filter(
|
||||
|
@ -409,9 +412,9 @@ function buildModuleSchema(
|
|||
aliasMap,
|
||||
tryParse,
|
||||
cxxOnly,
|
||||
language,
|
||||
resolveTypeAnnotation,
|
||||
translateTypeAnnotation,
|
||||
parser,
|
||||
),
|
||||
}));
|
||||
})
|
||||
|
|
|
@ -10,10 +10,17 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import type {UnionTypeAnnotationMemberType} from '../../CodegenSchema.js';
|
||||
import type {
|
||||
UnionTypeAnnotationMemberType,
|
||||
SchemaType,
|
||||
} from '../../CodegenSchema';
|
||||
import type {ParserType} from '../errors';
|
||||
import type {Parser} from '../parser';
|
||||
|
||||
const {buildSchema} = require('./buildSchema');
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
const {
|
||||
UnsupportedObjectPropertyTypeAnnotationParserError,
|
||||
} = require('../errors');
|
||||
|
@ -75,6 +82,12 @@ class FlowParser implements Parser {
|
|||
|
||||
return [...new Set(membersTypes.map(remapLiteral))];
|
||||
}
|
||||
|
||||
parseFile(filename: string): SchemaType {
|
||||
const contents = fs.readFileSync(filename, 'utf8');
|
||||
|
||||
return buildSchema(contents, filename, this);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import type {UnionTypeAnnotationMemberType} from '../CodegenSchema.js';
|
||||
import type {UnionTypeAnnotationMemberType, SchemaType} from '../CodegenSchema';
|
||||
import type {ParserType} from './errors';
|
||||
|
||||
/**
|
||||
|
@ -71,4 +71,10 @@ export interface Parser {
|
|||
remapUnionTypeAnnotationMemberNames(
|
||||
types: $FlowFixMe,
|
||||
): UnionTypeAnnotationMemberType[];
|
||||
/**
|
||||
* Given the content of a file and options, it returns an AST.
|
||||
* @parameter contents: the content of the file.
|
||||
* @returns: the AST of the file (given in program property for typescript).
|
||||
*/
|
||||
parseFile(filename: string): SchemaType;
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import type {UnionTypeAnnotationMemberType} from '../CodegenSchema.js';
|
||||
import type {Parser} from './parser';
|
||||
import type {ParserType} from './errors';
|
||||
import type {UnionTypeAnnotationMemberType, SchemaType} from '../CodegenSchema';
|
||||
|
||||
const {
|
||||
UnsupportedObjectPropertyTypeAnnotationParserError,
|
||||
|
@ -64,4 +64,22 @@ export class MockedParser implements Parser {
|
|||
): UnionTypeAnnotationMemberType[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
parseFile(filename: string): SchemaType {
|
||||
return {
|
||||
modules: {
|
||||
StringPropNativeComponentView: {
|
||||
type: 'Component',
|
||||
components: {
|
||||
StringPropNativeComponentView: {
|
||||
extendsProps: [],
|
||||
events: [],
|
||||
props: [],
|
||||
commands: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,6 +152,7 @@ function parseObjectProperty(
|
|||
aliasMap,
|
||||
tryParse,
|
||||
cxxOnly,
|
||||
parser,
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -262,32 +263,36 @@ function translateFunctionTypeAnnotation(
|
|||
tryParse: ParserErrorCapturer,
|
||||
cxxOnly: boolean,
|
||||
translateTypeAnnotation: $FlowFixMe,
|
||||
language: ParserType,
|
||||
parser: Parser,
|
||||
): NativeModuleFunctionTypeAnnotation {
|
||||
type Param = NamedShape<Nullable<NativeModuleParamTypeAnnotation>>;
|
||||
const params: Array<Param> = [];
|
||||
|
||||
for (const param of getTypeAnnotationParameters(typeAnnotation, language)) {
|
||||
for (const param of getTypeAnnotationParameters(
|
||||
typeAnnotation,
|
||||
parser.language(),
|
||||
)) {
|
||||
const parsedParam = tryParse(() => {
|
||||
if (getFunctionNameFromParameter(param, language) == null) {
|
||||
if (getFunctionNameFromParameter(param, parser.language()) == null) {
|
||||
throw new UnnamedFunctionParamParserError(
|
||||
param,
|
||||
hasteModuleName,
|
||||
language,
|
||||
parser.language(),
|
||||
);
|
||||
}
|
||||
|
||||
const paramName = getParameterName(param, language);
|
||||
const paramName = getParameterName(param, parser.language());
|
||||
|
||||
const [paramTypeAnnotation, isParamTypeAnnotationNullable] =
|
||||
unwrapNullable<$FlowFixMe>(
|
||||
translateTypeAnnotation(
|
||||
hasteModuleName,
|
||||
getParameterTypeAnnotation(param, language),
|
||||
getParameterTypeAnnotation(param, parser.language()),
|
||||
types,
|
||||
aliasMap,
|
||||
tryParse,
|
||||
cxxOnly,
|
||||
parser,
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -322,11 +327,12 @@ function translateFunctionTypeAnnotation(
|
|||
unwrapNullable<$FlowFixMe>(
|
||||
translateTypeAnnotation(
|
||||
hasteModuleName,
|
||||
getTypeAnnotationReturnType(typeAnnotation, language),
|
||||
getTypeAnnotationReturnType(typeAnnotation, parser.language()),
|
||||
types,
|
||||
aliasMap,
|
||||
tryParse,
|
||||
cxxOnly,
|
||||
parser,
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -334,7 +340,7 @@ function translateFunctionTypeAnnotation(
|
|||
hasteModuleName,
|
||||
typeAnnotation,
|
||||
'FunctionTypeAnnotation',
|
||||
language,
|
||||
parser.language(),
|
||||
cxxOnly,
|
||||
returnTypeAnnotation.type,
|
||||
);
|
||||
|
@ -361,15 +367,15 @@ function buildPropertySchema(
|
|||
aliasMap: {...NativeModuleAliasMap},
|
||||
tryParse: ParserErrorCapturer,
|
||||
cxxOnly: boolean,
|
||||
language: ParserType,
|
||||
resolveTypeAnnotation: $FlowFixMe,
|
||||
translateTypeAnnotation: $FlowFixMe,
|
||||
parser: Parser,
|
||||
): NativeModulePropertyShape {
|
||||
let nullable: boolean = false;
|
||||
let {key, value} = property;
|
||||
const methodName: string = key.name;
|
||||
|
||||
if (language === 'TypeScript') {
|
||||
if (parser.language() === 'TypeScript') {
|
||||
value =
|
||||
property.type === 'TSMethodSignature'
|
||||
? property
|
||||
|
@ -383,7 +389,7 @@ function buildPropertySchema(
|
|||
property.value,
|
||||
key.name,
|
||||
value.type,
|
||||
language,
|
||||
parser.language(),
|
||||
);
|
||||
|
||||
return {
|
||||
|
@ -399,7 +405,7 @@ function buildPropertySchema(
|
|||
tryParse,
|
||||
cxxOnly,
|
||||
translateTypeAnnotation,
|
||||
language,
|
||||
parser,
|
||||
),
|
||||
),
|
||||
};
|
||||
|
|
|
@ -31,7 +31,6 @@ import type {
|
|||
StringTypeAnnotation,
|
||||
VoidTypeAnnotation,
|
||||
} from '../CodegenSchema';
|
||||
import type {ParserType} from './errors';
|
||||
import type {Parser} from './parser';
|
||||
import type {
|
||||
ParserErrorCapturer,
|
||||
|
@ -105,7 +104,7 @@ function emitFunction(
|
|||
tryParse: ParserErrorCapturer,
|
||||
cxxOnly: boolean,
|
||||
translateTypeAnnotation: $FlowFixMe,
|
||||
language: ParserType,
|
||||
parser: Parser,
|
||||
): Nullable<NativeModuleFunctionTypeAnnotation> {
|
||||
const translateFunctionTypeAnnotationValue: NativeModuleFunctionTypeAnnotation =
|
||||
translateFunctionTypeAnnotation(
|
||||
|
@ -116,7 +115,7 @@ function emitFunction(
|
|||
tryParse,
|
||||
cxxOnly,
|
||||
translateTypeAnnotation,
|
||||
language,
|
||||
parser,
|
||||
);
|
||||
return wrapNullable(nullable, translateFunctionTypeAnnotationValue);
|
||||
}
|
||||
|
@ -225,6 +224,7 @@ function emitPromise(
|
|||
aliasMap,
|
||||
tryParse,
|
||||
cxxOnly,
|
||||
parser,
|
||||
),
|
||||
});
|
||||
} catch {
|
||||
|
@ -285,8 +285,8 @@ function translateArrayTypeAnnotation(
|
|||
arrayType: 'Array' | 'ReadonlyArray',
|
||||
elementType: $FlowFixMe,
|
||||
nullable: boolean,
|
||||
language: ParserType,
|
||||
translateTypeAnnotation: $FlowFixMe,
|
||||
parser: Parser,
|
||||
): Nullable<NativeModuleTypeAnnotation> {
|
||||
try {
|
||||
/**
|
||||
|
@ -310,6 +310,7 @@ function translateArrayTypeAnnotation(
|
|||
*/
|
||||
nullGuard,
|
||||
cxxOnly,
|
||||
parser,
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -318,7 +319,7 @@ function translateArrayTypeAnnotation(
|
|||
elementType,
|
||||
arrayType,
|
||||
_elementType.type,
|
||||
language,
|
||||
parser.language(),
|
||||
);
|
||||
|
||||
return wrapNullable(nullable, {
|
||||
|
@ -357,8 +358,8 @@ function emitArrayType(
|
|||
typeAnnotation.type,
|
||||
typeAnnotation.typeParameters.params[0],
|
||||
nullable,
|
||||
parser.language(),
|
||||
translateTypeAnnotation,
|
||||
parser,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {SchemaType} from '../../CodegenSchema';
|
||||
import type {Parser} from '../parser';
|
||||
|
||||
// $FlowFixMe[untyped-import] Use flow-types for @babel/parser
|
||||
const babelParser = require('@babel/parser');
|
||||
const {
|
||||
buildSchemaFromConfigType,
|
||||
getConfigType,
|
||||
isModuleRegistryCall,
|
||||
} = require('../utils');
|
||||
const {buildComponentSchema} = require('./components');
|
||||
const {wrapComponentSchema} = require('./components/schema');
|
||||
const {buildModuleSchema} = require('./modules');
|
||||
|
||||
function Visitor(infoMap: {isComponent: boolean, isModule: boolean}) {
|
||||
return {
|
||||
CallExpression(node: $FlowFixMe) {
|
||||
if (
|
||||
node.callee.type === 'Identifier' &&
|
||||
node.callee.name === 'codegenNativeComponent'
|
||||
) {
|
||||
infoMap.isComponent = true;
|
||||
}
|
||||
|
||||
if (isModuleRegistryCall(node)) {
|
||||
infoMap.isModule = true;
|
||||
}
|
||||
},
|
||||
|
||||
TSInterfaceDeclaration(node: $FlowFixMe) {
|
||||
if (
|
||||
Array.isArray(node.extends) &&
|
||||
node.extends.some(
|
||||
extension => extension.expression.name === 'TurboModule',
|
||||
)
|
||||
) {
|
||||
infoMap.isModule = true;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function buildSchema(
|
||||
contents: string,
|
||||
filename: ?string,
|
||||
parser: Parser,
|
||||
): SchemaType {
|
||||
// Early return for non-Spec JavaScript files
|
||||
if (
|
||||
!contents.includes('codegenNativeComponent') &&
|
||||
!contents.includes('TurboModule')
|
||||
) {
|
||||
return {modules: {}};
|
||||
}
|
||||
|
||||
const ast = babelParser.parse(contents, {
|
||||
sourceType: 'module',
|
||||
plugins: ['typescript'],
|
||||
}).program;
|
||||
|
||||
const configType = getConfigType(ast, Visitor);
|
||||
|
||||
return buildSchemaFromConfigType(
|
||||
configType,
|
||||
filename,
|
||||
ast,
|
||||
wrapComponentSchema,
|
||||
buildComponentSchema,
|
||||
buildModuleSchema,
|
||||
parser,
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
buildSchema,
|
||||
};
|
|
@ -11,8 +11,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const TypeScriptParser = require('../../index.js');
|
||||
const {parseFile} = require('../../../utils.js');
|
||||
const {TypeScriptParser} = require('../../parser');
|
||||
const fixtures = require('../__test_fixtures__/fixtures.js');
|
||||
const failureFixtures = require('../__test_fixtures__/failures.js');
|
||||
jest.mock('fs', () => ({
|
||||
|
@ -26,12 +25,14 @@ jest.mock('fs', () => ({
|
|||
},
|
||||
}));
|
||||
|
||||
const parser = new TypeScriptParser();
|
||||
|
||||
describe('RN Codegen TypeScript Parser', () => {
|
||||
Object.keys(fixtures)
|
||||
.sort()
|
||||
.forEach(fixtureName => {
|
||||
it(`can generate fixture ${fixtureName}`, () => {
|
||||
const schema = parseFile(fixtureName, TypeScriptParser.buildSchema);
|
||||
const schema = parser.parseFile(fixtureName);
|
||||
const serializedSchema = JSON.stringify(schema, null, 2).replace(
|
||||
/"/g,
|
||||
"'",
|
||||
|
@ -45,7 +46,7 @@ describe('RN Codegen TypeScript Parser', () => {
|
|||
.forEach(fixtureName => {
|
||||
it(`Fails with error message ${fixtureName}`, () => {
|
||||
expect(() => {
|
||||
parseFile(fixtureName, TypeScriptParser.buildSchema);
|
||||
parser.parseFile(fixtureName);
|
||||
}).toThrowErrorMatchingSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
|
@ -17,6 +17,7 @@ import type {
|
|||
import type {TypeDeclarationMap} from '../../utils';
|
||||
const {parseTopLevelType} = require('../parseTopLevelType');
|
||||
|
||||
// $FlowFixMe[unclear-type] there's no flowtype for ASTs
|
||||
type EventTypeAST = Object;
|
||||
|
||||
function buildCommandSchemaInternal(
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
|
@ -12,83 +12,23 @@
|
|||
|
||||
import type {SchemaType} from '../../CodegenSchema.js';
|
||||
|
||||
const babelParser = require('@babel/parser');
|
||||
const fs = require('fs');
|
||||
const {
|
||||
buildSchemaFromConfigType,
|
||||
getConfigType,
|
||||
isModuleRegistryCall,
|
||||
} = require('../utils');
|
||||
const {buildComponentSchema} = require('./components');
|
||||
const {wrapComponentSchema} = require('./components/schema');
|
||||
const {buildModuleSchema} = require('./modules');
|
||||
const {buildSchema} = require('./buildSchema');
|
||||
const {TypeScriptParser} = require('./parser');
|
||||
|
||||
function Visitor(infoMap: {isComponent: boolean, isModule: boolean}) {
|
||||
return {
|
||||
CallExpression(node: $FlowFixMe) {
|
||||
if (
|
||||
node.callee.type === 'Identifier' &&
|
||||
node.callee.name === 'codegenNativeComponent'
|
||||
) {
|
||||
infoMap.isComponent = true;
|
||||
}
|
||||
|
||||
if (isModuleRegistryCall(node)) {
|
||||
infoMap.isModule = true;
|
||||
}
|
||||
},
|
||||
|
||||
TSInterfaceDeclaration(node: $FlowFixMe) {
|
||||
if (
|
||||
Array.isArray(node.extends) &&
|
||||
node.extends.some(
|
||||
extension => extension.expression.name === 'TurboModule',
|
||||
)
|
||||
) {
|
||||
infoMap.isModule = true;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function buildSchema(contents: string, filename: ?string): SchemaType {
|
||||
// Early return for non-Spec JavaScript files
|
||||
if (
|
||||
!contents.includes('codegenNativeComponent') &&
|
||||
!contents.includes('TurboModule')
|
||||
) {
|
||||
return {modules: {}};
|
||||
}
|
||||
|
||||
const ast = babelParser.parse(contents, {
|
||||
sourceType: 'module',
|
||||
plugins: ['typescript'],
|
||||
}).program;
|
||||
|
||||
const configType = getConfigType(ast, Visitor);
|
||||
|
||||
return buildSchemaFromConfigType(
|
||||
configType,
|
||||
filename,
|
||||
ast,
|
||||
wrapComponentSchema,
|
||||
buildComponentSchema,
|
||||
buildModuleSchema,
|
||||
);
|
||||
}
|
||||
const parser = new TypeScriptParser();
|
||||
|
||||
function parseModuleFixture(filename: string): SchemaType {
|
||||
const contents = fs.readFileSync(filename, 'utf8');
|
||||
|
||||
return buildSchema(contents, 'path/NativeSampleTurboModule.ts');
|
||||
return buildSchema(contents, 'path/NativeSampleTurboModule.ts', parser);
|
||||
}
|
||||
|
||||
function parseString(contents: string, filename: ?string): SchemaType {
|
||||
return buildSchema(contents, filename);
|
||||
return buildSchema(contents, filename, parser);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
buildSchema,
|
||||
parseModuleFixture,
|
||||
parseString,
|
||||
};
|
||||
|
|
|
@ -20,6 +20,7 @@ import type {
|
|||
Nullable,
|
||||
} from '../../../CodegenSchema';
|
||||
|
||||
import type {Parser} from '../../parser';
|
||||
import type {ParserErrorCapturer, TypeDeclarationMap} from '../../utils';
|
||||
|
||||
const {visit, isModuleRegistryCall, verifyPlatforms} = require('../../utils');
|
||||
|
@ -68,10 +69,7 @@ const {
|
|||
throwIfIncorrectModuleRegistryCallTypeParameterParserError,
|
||||
} = require('../../error-utils');
|
||||
|
||||
const {TypeScriptParser} = require('../parser');
|
||||
|
||||
const language = 'TypeScript';
|
||||
const parser = new TypeScriptParser();
|
||||
|
||||
function translateTypeAnnotation(
|
||||
hasteModuleName: string,
|
||||
|
@ -83,6 +81,7 @@ function translateTypeAnnotation(
|
|||
aliasMap: {...NativeModuleAliasMap},
|
||||
tryParse: ParserErrorCapturer,
|
||||
cxxOnly: boolean,
|
||||
parser: Parser,
|
||||
): Nullable<NativeModuleTypeAnnotation> {
|
||||
const {nullable, typeAnnotation, typeAliasResolutionStatus} =
|
||||
resolveTypeAnnotation(typeScriptTypeAnnotation, types);
|
||||
|
@ -97,8 +96,8 @@ function translateTypeAnnotation(
|
|||
'Array',
|
||||
typeAnnotation.elementType,
|
||||
nullable,
|
||||
language,
|
||||
translateTypeAnnotation,
|
||||
parser,
|
||||
);
|
||||
}
|
||||
case 'TSTypeOperator': {
|
||||
|
@ -114,8 +113,8 @@ function translateTypeAnnotation(
|
|||
'ReadonlyArray',
|
||||
typeAnnotation.typeAnnotation.elementType,
|
||||
nullable,
|
||||
language,
|
||||
translateTypeAnnotation,
|
||||
parser,
|
||||
);
|
||||
} else {
|
||||
throw new UnsupportedGenericParserError(
|
||||
|
@ -200,6 +199,7 @@ function translateTypeAnnotation(
|
|||
aliasMap,
|
||||
tryParse,
|
||||
cxxOnly,
|
||||
parser,
|
||||
);
|
||||
// no need to do further checking
|
||||
return emitObject(nullable);
|
||||
|
@ -259,7 +259,7 @@ function translateTypeAnnotation(
|
|||
tryParse,
|
||||
cxxOnly,
|
||||
translateTypeAnnotation,
|
||||
language,
|
||||
parser,
|
||||
);
|
||||
}
|
||||
case 'TSUnionType': {
|
||||
|
@ -297,6 +297,7 @@ function buildModuleSchema(
|
|||
*/
|
||||
ast: $FlowFixMe,
|
||||
tryParse: ParserErrorCapturer,
|
||||
parser: Parser,
|
||||
): NativeModuleSchema {
|
||||
const types = getTypes(ast);
|
||||
const moduleSpecs = (Object.values(types): $ReadOnlyArray<$FlowFixMe>).filter(
|
||||
|
@ -421,9 +422,9 @@ function buildModuleSchema(
|
|||
aliasMap,
|
||||
tryParse,
|
||||
cxxOnly,
|
||||
language,
|
||||
resolveTypeAnnotation,
|
||||
translateTypeAnnotation,
|
||||
parser,
|
||||
),
|
||||
}));
|
||||
})
|
||||
|
|
|
@ -10,10 +10,17 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import type {UnionTypeAnnotationMemberType} from '../../CodegenSchema.js';
|
||||
import type {
|
||||
UnionTypeAnnotationMemberType,
|
||||
SchemaType,
|
||||
} from '../../CodegenSchema';
|
||||
import type {ParserType} from '../errors';
|
||||
import type {Parser} from '../parser';
|
||||
|
||||
const {buildSchema} = require('./buildSchema');
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
const {
|
||||
UnsupportedObjectPropertyTypeAnnotationParserError,
|
||||
} = require('../errors');
|
||||
|
@ -81,6 +88,12 @@ class TypeScriptParser implements Parser {
|
|||
|
||||
return [...new Set(membersTypes.map(remapLiteral))];
|
||||
}
|
||||
|
||||
parseFile(filename: string): SchemaType {
|
||||
const contents = fs.readFileSync(filename, 'utf8');
|
||||
|
||||
return buildSchema(contents, filename, this);
|
||||
}
|
||||
}
|
||||
module.exports = {
|
||||
TypeScriptParser,
|
||||
|
|
|
@ -17,7 +17,6 @@ const {parseTopLevelType} = require('./parseTopLevelType');
|
|||
/**
|
||||
* TODO(T108222691): Use flow-types for @babel/parser
|
||||
*/
|
||||
|
||||
function getTypes(ast: $FlowFixMe): TypeDeclarationMap {
|
||||
return ast.body.reduce((types, node) => {
|
||||
switch (node.type) {
|
||||
|
|
|
@ -12,10 +12,11 @@
|
|||
|
||||
import type {ComponentSchemaBuilderConfig} from './flow/components/schema';
|
||||
import type {NativeModuleSchema, SchemaType} from '../CodegenSchema';
|
||||
import type {Parser} from './parser';
|
||||
|
||||
const {ParserError} = require('./errors');
|
||||
const {wrapModuleSchema} = require('./parsers-commons');
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const invariant = require('invariant');
|
||||
|
||||
|
@ -95,15 +96,6 @@ function verifyPlatforms(
|
|||
};
|
||||
}
|
||||
|
||||
function parseFile(
|
||||
filename: string,
|
||||
callback: (contents: string, filename: string) => SchemaType,
|
||||
): SchemaType {
|
||||
const contents = fs.readFileSync(filename, 'utf8');
|
||||
|
||||
return callback(contents, filename);
|
||||
}
|
||||
|
||||
// TODO(T108222691): Use flow-types for @babel/parser
|
||||
function visit(
|
||||
astNode: $FlowFixMe,
|
||||
|
@ -143,7 +135,9 @@ function buildSchemaFromConfigType(
|
|||
hasteModuleName: string,
|
||||
ast: $FlowFixMe,
|
||||
tryParse: ParserErrorCapturer,
|
||||
parser: Parser,
|
||||
) => NativeModuleSchema,
|
||||
parser: Parser,
|
||||
): SchemaType {
|
||||
switch (configType) {
|
||||
case 'component': {
|
||||
|
@ -158,7 +152,7 @@ function buildSchemaFromConfigType(
|
|||
const [parsingErrors, tryParse] = createParserErrorCapturer();
|
||||
|
||||
const schema = tryParse(() =>
|
||||
buildModuleSchema(nativeModuleName, ast, tryParse),
|
||||
buildModuleSchema(nativeModuleName, ast, tryParse, parser),
|
||||
);
|
||||
|
||||
if (parsingErrors.length > 0) {
|
||||
|
@ -259,7 +253,6 @@ module.exports = {
|
|||
extractNativeModuleName,
|
||||
createParserErrorCapturer,
|
||||
verifyPlatforms,
|
||||
parseFile,
|
||||
visit,
|
||||
buildSchemaFromConfigType,
|
||||
isModuleRegistryCall,
|
||||
|
|
Загрузка…
Ссылка в новой задаче