add handleGenericTypeAnnotation in parser-commons (#37525)
Summary: Part of https://github.com/facebook/react-native/issues/34872 Move the switch construct from [parsers/typescript/utils.js](e133100721/packages/react-native-codegen/src/parsers/typescript/utils.js (L59-L93)
) and [parsers/flow/utils.js](e133100721/packages/react-native-codegen/src/parsers/flow/utils.js (L56-L81)
) to the parsers-commons.js file, in a handleGenericTypeAnnotation function. Use that function in place of the switch. ## 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][Added]: Added handleGenericTypeAnnotation in parsers-commons Pull Request resolved: https://github.com/facebook/react-native/pull/37525 Test Plan: `yarn test` Reviewed By: cortinico Differential Revision: D46264650 Pulled By: cipolleschi fbshipit-source-id: a315ee8cad24d91c9e98e5533d4cdc8b43ebc9a0
This commit is contained in:
Родитель
0af806e96c
Коммит
8ffaede05a
|
@ -25,6 +25,8 @@ import {
|
|||
getCommandOptions,
|
||||
getOptions,
|
||||
getCommandTypeNameAndOptionsExpression,
|
||||
getTypeResolutionStatus,
|
||||
handleGenericTypeAnnotation,
|
||||
} from '../parsers-commons';
|
||||
import type {ParserType} from '../errors';
|
||||
|
||||
|
@ -1544,3 +1546,120 @@ describe('getCommandTypeNameAndOptionsExpression', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTypeResolutionStatus', () => {
|
||||
it('returns type resolution status for a type declaration', () => {
|
||||
const typeAnnotation = {
|
||||
id: {
|
||||
name: 'TypeAnnotationName',
|
||||
},
|
||||
};
|
||||
expect(
|
||||
getTypeResolutionStatus('alias', typeAnnotation, flowParser),
|
||||
).toEqual({
|
||||
successful: true,
|
||||
type: 'alias',
|
||||
name: 'TypeAnnotationName',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns type resolution status for an enum declaration', () => {
|
||||
const typeAnnotation = {
|
||||
id: {
|
||||
name: 'TypeAnnotationName',
|
||||
},
|
||||
};
|
||||
expect(getTypeResolutionStatus('enum', typeAnnotation, flowParser)).toEqual(
|
||||
{
|
||||
successful: true,
|
||||
type: 'enum',
|
||||
name: 'TypeAnnotationName',
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleGenericTypeAnnotation', () => {
|
||||
it('returns when TypeAnnotation is a type declaration', () => {
|
||||
const typeAnnotation = {
|
||||
id: {
|
||||
name: 'TypeAnnotationName',
|
||||
},
|
||||
};
|
||||
const resolvedTypeAnnotation = {
|
||||
type: 'TypeAlias',
|
||||
right: {
|
||||
type: 'TypeAnnotation',
|
||||
},
|
||||
};
|
||||
expect(
|
||||
handleGenericTypeAnnotation(
|
||||
typeAnnotation,
|
||||
resolvedTypeAnnotation,
|
||||
flowParser,
|
||||
),
|
||||
).toEqual({
|
||||
typeAnnotation: {
|
||||
type: 'TypeAnnotation',
|
||||
},
|
||||
typeResolutionStatus: {
|
||||
successful: true,
|
||||
type: 'alias',
|
||||
name: 'TypeAnnotationName',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('returns when TypeAnnotation is an enum declaration', () => {
|
||||
const typeAnnotation = {
|
||||
id: {
|
||||
name: 'TypeAnnotationName',
|
||||
},
|
||||
};
|
||||
const resolvedTypeAnnotation = {
|
||||
type: 'EnumDeclaration',
|
||||
body: {
|
||||
type: 'TypeAnnotation',
|
||||
},
|
||||
};
|
||||
expect(
|
||||
handleGenericTypeAnnotation(
|
||||
typeAnnotation,
|
||||
resolvedTypeAnnotation,
|
||||
flowParser,
|
||||
),
|
||||
).toEqual({
|
||||
typeAnnotation: {
|
||||
type: 'TypeAnnotation',
|
||||
},
|
||||
typeResolutionStatus: {
|
||||
successful: true,
|
||||
type: 'enum',
|
||||
name: 'TypeAnnotationName',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('throws when the non GenericTypeAnnotation is unsupported', () => {
|
||||
const typeAnnotation = {
|
||||
type: 'UnsupportedTypeAnnotation',
|
||||
id: {
|
||||
name: 'UnsupportedType',
|
||||
},
|
||||
};
|
||||
const resolvedTypeAnnotation = {
|
||||
type: 'UnsupportedTypeAnnotation',
|
||||
};
|
||||
expect(() =>
|
||||
handleGenericTypeAnnotation(
|
||||
typeAnnotation,
|
||||
resolvedTypeAnnotation,
|
||||
flowParser,
|
||||
),
|
||||
).toThrow(
|
||||
new Error(
|
||||
parser.genericTypeAnnotationErrorMessage(resolvedTypeAnnotation),
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -55,11 +55,15 @@ const {flowTranslateTypeAnnotation} = require('./modules');
|
|||
// $FlowFixMe[untyped-import] there's no flowtype flow-parser
|
||||
const flowParser = require('flow-parser');
|
||||
|
||||
const {buildSchema, buildPropSchema} = require('../parsers-commons');
|
||||
const {
|
||||
buildSchema,
|
||||
buildPropSchema,
|
||||
buildModuleSchema,
|
||||
handleGenericTypeAnnotation,
|
||||
} = require('../parsers-commons');
|
||||
const {Visitor} = require('../parsers-primitives');
|
||||
const {buildComponentSchema} = require('./components');
|
||||
const {wrapComponentSchema} = require('../schema.js');
|
||||
const {buildModuleSchema} = require('../parsers-commons.js');
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
|
@ -411,36 +415,16 @@ class FlowParser implements Parser {
|
|||
break;
|
||||
}
|
||||
|
||||
const resolvedTypeAnnotation = types[node.id.name];
|
||||
const typeAnnotationName = this.nameForGenericTypeAnnotation(node);
|
||||
const resolvedTypeAnnotation = types[typeAnnotationName];
|
||||
if (resolvedTypeAnnotation == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (resolvedTypeAnnotation.type) {
|
||||
case parser.typeAlias: {
|
||||
typeResolutionStatus = {
|
||||
successful: true,
|
||||
type: 'alias',
|
||||
name: node.id.name,
|
||||
};
|
||||
node = resolvedTypeAnnotation.right;
|
||||
break;
|
||||
}
|
||||
case parser.enumDeclaration: {
|
||||
typeResolutionStatus = {
|
||||
successful: true,
|
||||
type: 'enum',
|
||||
name: node.id.name,
|
||||
};
|
||||
node = resolvedTypeAnnotation.body;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new TypeError(
|
||||
`A non GenericTypeAnnotation must be a type declaration ('${parser.typeAlias}') or enum ('${parser.enumDeclaration}'). Instead, got the unsupported ${resolvedTypeAnnotation.type}.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
const {typeAnnotation: typeAnnotationNode, typeResolutionStatus: status} =
|
||||
handleGenericTypeAnnotation(node, resolvedTypeAnnotation, this);
|
||||
typeResolutionStatus = status;
|
||||
node = typeAnnotationNode;
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -531,6 +515,18 @@ class FlowParser implements Parser {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
nextNodeForTypeAlias(typeAnnotation: $FlowFixMe): $FlowFixMe {
|
||||
return typeAnnotation.right;
|
||||
}
|
||||
|
||||
nextNodeForEnum(typeAnnotation: $FlowFixMe): $FlowFixMe {
|
||||
return typeAnnotation.body;
|
||||
}
|
||||
|
||||
genericTypeAnnotationErrorMessage(typeAnnotation: $FlowFixMe): string {
|
||||
return `A non GenericTypeAnnotation must be a type declaration ('${this.typeAlias}') or enum ('${this.enumDeclaration}'). Instead, got the unsupported ${typeAnnotation.type}.`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
|
|
@ -378,4 +378,19 @@ export interface Parser {
|
|||
};
|
||||
|
||||
getProperties(typeName: string, types: TypeDeclarationMap): $FlowFixMe;
|
||||
|
||||
/**
|
||||
* Given a typeAlias, it returns the next node.
|
||||
*/
|
||||
nextNodeForTypeAlias(typeAnnotation: $FlowFixMe): $FlowFixMe;
|
||||
|
||||
/**
|
||||
* Given an enum Declaration, it returns the next node.
|
||||
*/
|
||||
nextNodeForEnum(typeAnnotation: $FlowFixMe): $FlowFixMe;
|
||||
|
||||
/**
|
||||
* Given a unsupported typeAnnotation, returns an error message.
|
||||
*/
|
||||
genericTypeAnnotationErrorMessage(typeAnnotation: $FlowFixMe): string;
|
||||
}
|
||||
|
|
|
@ -456,4 +456,16 @@ export class MockedParser implements Parser {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
nextNodeForTypeAlias(typeAnnotation: $FlowFixMe): $FlowFixMe {
|
||||
return typeAnnotation.right;
|
||||
}
|
||||
|
||||
nextNodeForEnum(typeAnnotation: $FlowFixMe): $FlowFixMe {
|
||||
return typeAnnotation.body;
|
||||
}
|
||||
|
||||
genericTypeAnnotationErrorMessage(typeAnnotation: $FlowFixMe): string {
|
||||
return `A non GenericTypeAnnotation must be a type declaration ('${this.typeAlias}') or enum ('${this.enumDeclaration}'). Instead, got the unsupported ${typeAnnotation.type}.`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,12 @@ import type {
|
|||
|
||||
import type {Parser} from './parser';
|
||||
import type {ParserType} from './errors';
|
||||
import type {ParserErrorCapturer, TypeDeclarationMap, PropAST} from './utils';
|
||||
import type {
|
||||
ParserErrorCapturer,
|
||||
TypeDeclarationMap,
|
||||
PropAST,
|
||||
TypeResolutionStatus,
|
||||
} from './utils';
|
||||
import type {ComponentSchemaBuilderConfig} from './schema.js';
|
||||
|
||||
const {
|
||||
|
@ -983,6 +988,71 @@ function getCommandProperties(ast: $FlowFixMe, parser: Parser) {
|
|||
return properties;
|
||||
}
|
||||
|
||||
function getTypeResolutionStatus(
|
||||
type: 'alias' | 'enum',
|
||||
typeAnnotation: $FlowFixMe,
|
||||
parser: Parser,
|
||||
): TypeResolutionStatus {
|
||||
return {
|
||||
successful: true,
|
||||
type,
|
||||
name: parser.nameForGenericTypeAnnotation(typeAnnotation),
|
||||
};
|
||||
}
|
||||
|
||||
function handleGenericTypeAnnotation(
|
||||
typeAnnotation: $FlowFixMe,
|
||||
resolvedTypeAnnotation: TypeDeclarationMap,
|
||||
parser: Parser,
|
||||
): {
|
||||
typeAnnotation: $FlowFixMe,
|
||||
typeResolutionStatus: TypeResolutionStatus,
|
||||
} {
|
||||
let typeResolutionStatus;
|
||||
let node;
|
||||
|
||||
switch (resolvedTypeAnnotation.type) {
|
||||
case parser.typeAlias: {
|
||||
typeResolutionStatus = getTypeResolutionStatus(
|
||||
'alias',
|
||||
typeAnnotation,
|
||||
parser,
|
||||
);
|
||||
node = parser.nextNodeForTypeAlias(resolvedTypeAnnotation);
|
||||
break;
|
||||
}
|
||||
case parser.enumDeclaration: {
|
||||
typeResolutionStatus = getTypeResolutionStatus(
|
||||
'enum',
|
||||
typeAnnotation,
|
||||
parser,
|
||||
);
|
||||
node = parser.nextNodeForEnum(resolvedTypeAnnotation);
|
||||
break;
|
||||
}
|
||||
// parser.interfaceDeclaration is not used here because for flow it should fall through to default case and throw an error
|
||||
case 'TSInterfaceDeclaration': {
|
||||
typeResolutionStatus = getTypeResolutionStatus(
|
||||
'alias',
|
||||
typeAnnotation,
|
||||
parser,
|
||||
);
|
||||
node = resolvedTypeAnnotation;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new TypeError(
|
||||
parser.genericTypeAnnotationErrorMessage(resolvedTypeAnnotation),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
typeAnnotation: node,
|
||||
typeResolutionStatus,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
wrapModuleSchema,
|
||||
unwrapNullable,
|
||||
|
@ -1007,4 +1077,6 @@ module.exports = {
|
|||
getEventArgument,
|
||||
findComponentConfig,
|
||||
getCommandProperties,
|
||||
handleGenericTypeAnnotation,
|
||||
getTypeResolutionStatus,
|
||||
};
|
||||
|
|
|
@ -43,14 +43,15 @@ const {typeScriptTranslateTypeAnnotation} = require('./modules');
|
|||
// $FlowFixMe[untyped-import] Use flow-types for @babel/parser
|
||||
const babelParser = require('@babel/parser');
|
||||
|
||||
const {buildSchema} = require('../parsers-commons');
|
||||
const {Visitor} = require('../parsers-primitives');
|
||||
const {buildComponentSchema} = require('./components');
|
||||
const {wrapComponentSchema} = require('../schema.js');
|
||||
const {
|
||||
buildSchema,
|
||||
buildModuleSchema,
|
||||
extendsForProp,
|
||||
buildPropSchema,
|
||||
handleGenericTypeAnnotation,
|
||||
} = require('../parsers-commons.js');
|
||||
|
||||
const {parseTopLevelType} = require('./parseTopLevelType');
|
||||
|
@ -408,45 +409,16 @@ class TypeScriptParser implements Parser {
|
|||
break;
|
||||
}
|
||||
|
||||
const resolvedTypeAnnotation = types[node.typeName.name];
|
||||
const typeAnnotationName = this.nameForGenericTypeAnnotation(node);
|
||||
const resolvedTypeAnnotation = types[typeAnnotationName];
|
||||
if (resolvedTypeAnnotation == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (resolvedTypeAnnotation.type) {
|
||||
case parser.typeAlias: {
|
||||
typeResolutionStatus = {
|
||||
successful: true,
|
||||
type: 'alias',
|
||||
name: node.typeName.name,
|
||||
};
|
||||
node = resolvedTypeAnnotation.typeAnnotation;
|
||||
break;
|
||||
}
|
||||
case parser.interfaceDeclaration: {
|
||||
typeResolutionStatus = {
|
||||
successful: true,
|
||||
type: 'alias',
|
||||
name: node.typeName.name,
|
||||
};
|
||||
node = resolvedTypeAnnotation;
|
||||
break;
|
||||
}
|
||||
case parser.enumDeclaration: {
|
||||
typeResolutionStatus = {
|
||||
successful: true,
|
||||
type: 'enum',
|
||||
name: node.typeName.name,
|
||||
};
|
||||
node = resolvedTypeAnnotation;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new TypeError(
|
||||
`A non GenericTypeAnnotation must be a type declaration ('${parser.typeAlias}'), an interface ('${parser.interfaceDeclaration}'), or enum ('${parser.enumDeclaration}'). Instead, got the unsupported ${resolvedTypeAnnotation.type}.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
const {typeAnnotation: typeAnnotationNode, typeResolutionStatus: status} =
|
||||
handleGenericTypeAnnotation(node, resolvedTypeAnnotation, this);
|
||||
typeResolutionStatus = status;
|
||||
node = typeAnnotationNode;
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -559,6 +531,18 @@ class TypeScriptParser implements Parser {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
nextNodeForTypeAlias(typeAnnotation: $FlowFixMe): $FlowFixMe {
|
||||
return typeAnnotation.typeAnnotation;
|
||||
}
|
||||
|
||||
nextNodeForEnum(typeAnnotation: $FlowFixMe): $FlowFixMe {
|
||||
return typeAnnotation;
|
||||
}
|
||||
|
||||
genericTypeAnnotationErrorMessage(typeAnnotation: $FlowFixMe): string {
|
||||
return `A non GenericTypeAnnotation must be a type declaration ('${this.typeAlias}'), an interface ('${this.interfaceDeclaration}'), or enum ('${this.enumDeclaration}'). Instead, got the unsupported ${typeAnnotation.type}.`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
|
Загрузка…
Ссылка в новой задаче