Extract parseString and parseModuleFixture functions in typescript and flow parsers (#35928)

Summary:
This PR aims to extract parseString and parseModuleFixture functions into the typescript and flow parsers. This task was proposed in https://github.com/facebook/react-native/issues/35158 and helps https://github.com/facebook/react-native/issues/34872.

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->
[Internal] [Changed] - Extract parseString and parseModuleFixture functions in typescript and flow parsers

Pull Request resolved: https://github.com/facebook/react-native/pull/35928

Test Plan:
yarn test:
<img width="386" alt="image" src="https://user-images.githubusercontent.com/40902940/213889984-f0cadaff-4472-42d6-b55b-4901023aad1e.png">

yarn flow:
<img width="166" alt="image" src="https://user-images.githubusercontent.com/40902940/213889974-21ac2483-2731-4cb1-a2b5-195d98619649.png">

yarn lint:
<img width="514" alt="image" src="https://user-images.githubusercontent.com/40902940/213889980-090af354-346f-4a9c-90bc-7006899f0819.png">

Reviewed By: jacdebug

Differential Revision: D42673866

Pulled By: cipolleschi

fbshipit-source-id: f1b5f8a7b3944e7e8223b25c0fb9bf4e8b512aa7
This commit is contained in:
MaeIg 2023-01-25 12:38:52 -08:00 коммит произвёл Facebook GitHub Bot
Родитель 6f7428e27b
Коммит 462815001b
11 изменённых файлов: 96 добавлений и 129 удалений

Просмотреть файл

@ -9,21 +9,28 @@
'use strict'; 'use strict';
let flowParser, typeScriptParser, RNCodegen; let FlowParser, TypeScriptParser, RNCodegen;
const {basename} = require('path'); const {basename} = require('path');
try { try {
flowParser = require('@react-native/codegen/src/parsers/flow'); FlowParser =
typeScriptParser = require('@react-native/codegen/src/parsers/typescript'); require('@react-native/codegen/src/parsers/flow/parser').FlowParser;
TypeScriptParser =
require('@react-native/codegen/src/parsers/typescript/parser').TypeScriptParser;
RNCodegen = require('@react-native/codegen/src/generators/RNCodegen'); RNCodegen = require('@react-native/codegen/src/generators/RNCodegen');
} catch (e) { } catch (e) {
// Fallback to lib when source doesn't exit (e.g. when installed as a dev dependency) // Fallback to lib when source doesn't exit (e.g. when installed as a dev dependency)
flowParser = require('@react-native/codegen/lib/parsers/flow'); FlowParser =
typeScriptParser = require('@react-native/codegen/lib/parsers/typescript'); require('@react-native/codegen/lib/parsers/flow/parser').FlowParser;
TypeScriptParser =
require('@react-native/codegen/lib/parsers/typescript/parser').TypeScriptParser;
RNCodegen = require('@react-native/codegen/lib/generators/RNCodegen'); RNCodegen = require('@react-native/codegen/lib/generators/RNCodegen');
} }
const flowParser = new FlowParser();
const typeScriptParser = new TypeScriptParser();
function parseFile(filename, code) { function parseFile(filename, code) {
if (filename.endsWith('js')) { if (filename.endsWith('js')) {
return flowParser.parseString(code); return flowParser.parseString(code);

Просмотреть файл

@ -1,47 +0,0 @@
/**
* 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.js';
const fs = require('fs');
const {buildSchema} = require('../parsers-commons');
const {Visitor} = require('./Visitor');
const {FlowParser} = require('./parser');
const {buildComponentSchema} = require('./components');
const {wrapComponentSchema} = require('./components/schema');
const {buildModuleSchema} = require('./modules');
const parser = new FlowParser();
function parseModuleFixture(filename: string): SchemaType {
const contents = fs.readFileSync(filename, 'utf8');
return parseString(contents, 'path/NativeSampleTurboModule.js');
}
function parseString(contents: string, filename: ?string): SchemaType {
return buildSchema(
contents,
filename,
wrapComponentSchema,
buildComponentSchema,
buildModuleSchema,
Visitor,
parser,
);
}
module.exports = {
parseModuleFixture,
parseString,
};

Просмотреть файл

@ -15,7 +15,8 @@ import type {
NativeModuleParamTypeAnnotation, NativeModuleParamTypeAnnotation,
} from '../../../../CodegenSchema'; } from '../../../../CodegenSchema';
const {parseString} = require('../../index.js'); const invariant = require('invariant');
const {unwrapNullable} = require('../../../parsers-commons'); const {unwrapNullable} = require('../../../parsers-commons');
const { const {
UnsupportedGenericParserError, UnsupportedGenericParserError,
@ -23,7 +24,9 @@ const {
UnnamedFunctionParamParserError, UnnamedFunctionParamParserError,
MissingTypeParameterGenericParserError, MissingTypeParameterGenericParserError,
} = require('../../../errors'); } = require('../../../errors');
const invariant = require('invariant'); const {FlowParser} = require('../../parser');
const flowParser = new FlowParser();
type PrimitiveTypeAnnotationType = type PrimitiveTypeAnnotationType =
| 'StringTypeAnnotation' | 'StringTypeAnnotation'
@ -1229,7 +1232,7 @@ describe('Flow Module Parser', () => {
}); });
function parseModule(source: string) { function parseModule(source: string) {
const schema = parseString(source, `${MODULE_NAME}.js`); const schema = flowParser.parseString(source, `${MODULE_NAME}.js`);
const module = schema.modules.NativeFoo; const module = schema.modules.NativeFoo;
invariant( invariant(
module.type === 'NativeModule', module.type === 'NativeModule',

Просмотреть файл

@ -11,11 +11,13 @@
'use strict'; 'use strict';
const FlowParser = require('../../index.js'); const {FlowParser} = require('../../parser');
const fixtures = require('../__test_fixtures__/fixtures.js'); const fixtures = require('../__test_fixtures__/fixtures.js');
const failureFixtures = require('../__test_fixtures__/failures.js'); const failureFixtures = require('../__test_fixtures__/failures.js');
const flowParser = new FlowParser();
jest.mock('fs', () => ({ jest.mock('fs', () => ({
readFileSync: filename => { readFileSync: filename => {
// Jest in the OSS does not allow to capture variables in closures. // Jest in the OSS does not allow to capture variables in closures.
@ -32,7 +34,7 @@ describe('RN Codegen Flow Parser', () => {
.sort() .sort()
.forEach(fixtureName => { .forEach(fixtureName => {
it(`can generate fixture ${fixtureName}`, () => { it(`can generate fixture ${fixtureName}`, () => {
const schema = FlowParser.parseModuleFixture(fixtureName); const schema = flowParser.parseModuleFixture(fixtureName);
const serializedSchema = JSON.stringify(schema, null, 2).replace( const serializedSchema = JSON.stringify(schema, null, 2).replace(
/"/g, /"/g,
"'", "'",
@ -47,7 +49,7 @@ describe('RN Codegen Flow Parser', () => {
.forEach(fixtureName => { .forEach(fixtureName => {
it(`Fails with error message ${fixtureName}`, () => { it(`Fails with error message ${fixtureName}`, () => {
expect(() => { expect(() => {
FlowParser.parseModuleFixture(fixtureName); flowParser.parseModuleFixture(fixtureName);
}).toThrowErrorMatchingSnapshot(); }).toThrowErrorMatchingSnapshot();
}); });
}); });

Просмотреть файл

@ -96,6 +96,10 @@ class FlowParser implements Parser {
parseFile(filename: string): SchemaType { parseFile(filename: string): SchemaType {
const contents = fs.readFileSync(filename, 'utf8'); const contents = fs.readFileSync(filename, 'utf8');
return this.parseString(contents, filename);
}
parseString(contents: string, filename: ?string): SchemaType {
return buildSchema( return buildSchema(
contents, contents,
filename, filename,
@ -107,6 +111,12 @@ class FlowParser implements Parser {
); );
} }
parseModuleFixture(filename: string): SchemaType {
const contents = fs.readFileSync(filename, 'utf8');
return this.parseString(contents, 'path/NativeSampleTurboModule.js');
}
getAst(contents: string): $FlowFixMe { getAst(contents: string): $FlowFixMe {
return flowParser.parse(contents, { return flowParser.parse(contents, {
enums: true, enums: true,

Просмотреть файл

@ -78,11 +78,24 @@ export interface Parser {
types: $FlowFixMe, types: $FlowFixMe,
): UnionTypeAnnotationMemberType[]; ): UnionTypeAnnotationMemberType[];
/** /**
* Given the content of a file and options, it returns an AST. * Given the name of a file, it returns a Schema.
* @parameter contents: the content of the file. * @parameter filename: the name of the file.
* @returns: the AST of the file (given in program property for typescript). * @returns: the Schema of the file.
*/ */
parseFile(filename: string): SchemaType; parseFile(filename: string): SchemaType;
/**
* Given the content of a file, it returns a Schema.
* @parameter contents: the content of the file.
* @parameter filename: the name of the file.
* @returns: the Schema of the file.
*/
parseString(contents: string, filename: ?string): SchemaType;
/**
* Given the name of a file, it returns a Schema.
* @parameter filename: the name of the file.
* @returns: the Schema of the file.
*/
parseModuleFixture(filename: string): SchemaType;
/** /**
* Given the content of a file, it returns an AST. * Given the content of a file, it returns an AST.

Просмотреть файл

@ -26,6 +26,22 @@ const {
UnsupportedObjectPropertyTypeAnnotationParserError, UnsupportedObjectPropertyTypeAnnotationParserError,
} = require('./errors'); } = require('./errors');
const schemaMock = {
modules: {
StringPropNativeComponentView: {
type: 'Component',
components: {
StringPropNativeComponentView: {
extendsProps: [],
events: [],
props: [],
commands: [],
},
},
},
},
};
export class MockedParser implements Parser { export class MockedParser implements Parser {
typeParameterInstantiation: string = 'TypeParameterInstantiation'; typeParameterInstantiation: string = 'TypeParameterInstantiation';
@ -74,21 +90,15 @@ export class MockedParser implements Parser {
} }
parseFile(filename: string): SchemaType { parseFile(filename: string): SchemaType {
return { return schemaMock;
modules: { }
StringPropNativeComponentView: {
type: 'Component', parseString(contents: string, filename: ?string): SchemaType {
components: { return schemaMock;
StringPropNativeComponentView: { }
extendsProps: [],
events: [], parseModuleFixture(filename: string): SchemaType {
props: [], return schemaMock;
commands: [],
},
},
},
},
};
} }
getAst(contents: string): $FlowFixMe { getAst(contents: string): $FlowFixMe {

Просмотреть файл

@ -1,47 +0,0 @@
/**
* 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.js';
const fs = require('fs');
const {buildSchema} = require('../parsers-commons');
const {Visitor} = require('./Visitor');
const {TypeScriptParser} = require('./parser');
const {buildComponentSchema} = require('./components');
const {wrapComponentSchema} = require('./components/schema');
const {buildModuleSchema} = require('./modules');
const parser = new TypeScriptParser();
function parseModuleFixture(filename: string): SchemaType {
const contents = fs.readFileSync(filename, 'utf8');
return parseString(contents, 'path/NativeSampleTurboModule.ts');
}
function parseString(contents: string, filename: ?string): SchemaType {
return buildSchema(
contents,
filename,
wrapComponentSchema,
buildComponentSchema,
buildModuleSchema,
Visitor,
parser,
);
}
module.exports = {
parseModuleFixture,
parseString,
};

Просмотреть файл

@ -15,7 +15,8 @@ import type {
NativeModuleParamTypeAnnotation, NativeModuleParamTypeAnnotation,
} from '../../../../CodegenSchema'; } from '../../../../CodegenSchema';
const {parseString} = require('../../index.js'); const invariant = require('invariant');
const {unwrapNullable} = require('../../../parsers-commons'); const {unwrapNullable} = require('../../../parsers-commons');
const { const {
UnsupportedGenericParserError, UnsupportedGenericParserError,
@ -23,7 +24,9 @@ const {
UnnamedFunctionParamParserError, UnnamedFunctionParamParserError,
MissingTypeParameterGenericParserError, MissingTypeParameterGenericParserError,
} = require('../../../errors'); } = require('../../../errors');
const invariant = require('invariant'); const {TypeScriptParser} = require('../../parser');
const typescriptParser = new TypeScriptParser();
type PrimitiveTypeAnnotationType = type PrimitiveTypeAnnotationType =
| 'StringTypeAnnotation' | 'StringTypeAnnotation'
@ -1228,7 +1231,7 @@ describe('TypeScript Module Parser', () => {
}); });
function parseModule(source: string) { function parseModule(source: string) {
const schema = parseString(source, `${MODULE_NAME}.ts`); const schema = typescriptParser.parseString(source, `${MODULE_NAME}.ts`);
const module = schema.modules.NativeFoo; const module = schema.modules.NativeFoo;
invariant( invariant(
module.type === 'NativeModule', module.type === 'NativeModule',

Просмотреть файл

@ -11,10 +11,13 @@
'use strict'; 'use strict';
const TypeScriptParser = require('../../index.js'); const {TypeScriptParser} = require('../../parser');
const fixtures = require('../__test_fixtures__/fixtures.js'); const fixtures = require('../__test_fixtures__/fixtures.js');
const failureFixtures = require('../__test_fixtures__/failures.js'); const failureFixtures = require('../__test_fixtures__/failures.js');
const typeScriptParser = new TypeScriptParser();
jest.mock('fs', () => ({ jest.mock('fs', () => ({
readFileSync: filename => { readFileSync: filename => {
// Jest in the OSS does not allow to capture variables in closures. // Jest in the OSS does not allow to capture variables in closures.
@ -31,7 +34,7 @@ describe('RN Codegen TypeScript Parser', () => {
.sort() .sort()
.forEach(fixtureName => { .forEach(fixtureName => {
it(`can generate fixture ${fixtureName}`, () => { it(`can generate fixture ${fixtureName}`, () => {
const schema = TypeScriptParser.parseModuleFixture(fixtureName); const schema = typeScriptParser.parseModuleFixture(fixtureName);
const serializedSchema = JSON.stringify(schema, null, 2).replace( const serializedSchema = JSON.stringify(schema, null, 2).replace(
/"/g, /"/g,
"'", "'",
@ -46,7 +49,7 @@ describe('RN Codegen TypeScript Parser', () => {
.forEach(fixtureName => { .forEach(fixtureName => {
it(`Fails with error message ${fixtureName}`, () => { it(`Fails with error message ${fixtureName}`, () => {
expect(() => { expect(() => {
TypeScriptParser.parseModuleFixture(fixtureName); typeScriptParser.parseModuleFixture(fixtureName);
}).toThrowErrorMatchingSnapshot(); }).toThrowErrorMatchingSnapshot();
}); });
}); });

Просмотреть файл

@ -102,6 +102,10 @@ class TypeScriptParser implements Parser {
parseFile(filename: string): SchemaType { parseFile(filename: string): SchemaType {
const contents = fs.readFileSync(filename, 'utf8'); const contents = fs.readFileSync(filename, 'utf8');
return this.parseString(contents, filename);
}
parseString(contents: string, filename: ?string): SchemaType {
return buildSchema( return buildSchema(
contents, contents,
filename, filename,
@ -113,6 +117,12 @@ class TypeScriptParser implements Parser {
); );
} }
parseModuleFixture(filename: string): SchemaType {
const contents = fs.readFileSync(filename, 'utf8');
return this.parseString(contents, 'path/NativeSampleTurboModule.ts');
}
getAst(contents: string): $FlowFixMe { getAst(contents: string): $FlowFixMe {
return babelParser.parse(contents, { return babelParser.parse(contents, {
sourceType: 'module', sourceType: 'module',