Skip to content

Commit d95cd99

Browse files
committed
codegen: add handleGenericTypeAnnotation in parser-commons
1 parent af6ef85 commit d95cd99

File tree

4 files changed

+221
-65
lines changed

4 files changed

+221
-65
lines changed

packages/react-native-codegen/src/parsers/__tests__/parsers-commons-test.js

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import {
2525
getCommandOptions,
2626
getOptions,
2727
getCommandTypeNameAndOptionsExpression,
28+
getTypeResolutionStatus,
29+
handleGenericTypeAnnotation,
2830
} from '../parsers-commons';
2931
import type {ParserType} from '../errors';
3032

@@ -1544,3 +1546,120 @@ describe('getCommandTypeNameAndOptionsExpression', () => {
15441546
});
15451547
});
15461548
});
1549+
1550+
describe('getTypeResolutionStatus', () => {
1551+
it('returns type resolution status for a type declaration', () => {
1552+
const typeAnnotation = {
1553+
id: {
1554+
name: 'TypeAnnotationName',
1555+
},
1556+
};
1557+
expect(
1558+
getTypeResolutionStatus('alias', typeAnnotation, flowParser),
1559+
).toEqual({
1560+
successful: true,
1561+
type: 'alias',
1562+
name: 'TypeAnnotationName',
1563+
});
1564+
});
1565+
1566+
it('returns type resolution status for an enum declaration', () => {
1567+
const typeAnnotation = {
1568+
id: {
1569+
name: 'TypeAnnotationName',
1570+
},
1571+
};
1572+
expect(getTypeResolutionStatus('enum', typeAnnotation, flowParser)).toEqual(
1573+
{
1574+
successful: true,
1575+
type: 'enum',
1576+
name: 'TypeAnnotationName',
1577+
},
1578+
);
1579+
});
1580+
});
1581+
1582+
describe('handleGenericTypeAnnotation', () => {
1583+
it('returns when TypeAnnotation is a type declaration', () => {
1584+
const typeAnnotation = {
1585+
id: {
1586+
name: 'TypeAnnotationName',
1587+
},
1588+
};
1589+
const resolvedTypeAnnotation = {
1590+
type: 'TypeAlias',
1591+
right: {
1592+
type: 'TypeAnnotation',
1593+
},
1594+
};
1595+
expect(
1596+
handleGenericTypeAnnotation(
1597+
typeAnnotation,
1598+
resolvedTypeAnnotation,
1599+
flowParser,
1600+
),
1601+
).toEqual({
1602+
typeAnnotation: {
1603+
type: 'TypeAnnotation',
1604+
},
1605+
typeResolutionStatus: {
1606+
successful: true,
1607+
type: 'alias',
1608+
name: 'TypeAnnotationName',
1609+
},
1610+
});
1611+
});
1612+
1613+
it('returns when TypeAnnotation is an enum declaration', () => {
1614+
const typeAnnotation = {
1615+
id: {
1616+
name: 'TypeAnnotationName',
1617+
},
1618+
};
1619+
const resolvedTypeAnnotation = {
1620+
type: 'EnumDeclaration',
1621+
body: {
1622+
type: 'TypeAnnotation',
1623+
},
1624+
};
1625+
expect(
1626+
handleGenericTypeAnnotation(
1627+
typeAnnotation,
1628+
resolvedTypeAnnotation,
1629+
flowParser,
1630+
),
1631+
).toEqual({
1632+
typeAnnotation: {
1633+
type: 'TypeAnnotation',
1634+
},
1635+
typeResolutionStatus: {
1636+
successful: true,
1637+
type: 'enum',
1638+
name: 'TypeAnnotationName',
1639+
},
1640+
});
1641+
});
1642+
1643+
it('throws when the non GenericTypeAnnotation is unsupported', () => {
1644+
const typeAnnotation = {
1645+
type: 'UnsupportedTypeAnnotation',
1646+
id: {
1647+
name: 'UnsupportedType',
1648+
},
1649+
};
1650+
const resolvedTypeAnnotation = {
1651+
type: 'UnsupportedTypeAnnotation',
1652+
};
1653+
expect(() =>
1654+
handleGenericTypeAnnotation(
1655+
typeAnnotation,
1656+
resolvedTypeAnnotation,
1657+
flowParser,
1658+
),
1659+
).toThrow(
1660+
new Error(
1661+
`A non GenericTypeAnnotation must be a type declaration ('${flowParser.typeAlias}') or enum ('${flowParser.enumDeclaration}'). Instead, got the unsupported ${resolvedTypeAnnotation.type}.`,
1662+
),
1663+
);
1664+
});
1665+
});

packages/react-native-codegen/src/parsers/flow/parser.js

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,14 @@ const {flowTranslateTypeAnnotation} = require('./modules');
4747
// $FlowFixMe[untyped-import] there's no flowtype flow-parser
4848
const flowParser = require('flow-parser');
4949

50-
const {buildSchema} = require('../parsers-commons');
50+
const {
51+
buildSchema,
52+
buildModuleSchema,
53+
handleGenericTypeAnnotation,
54+
} = require('../parsers-commons');
5155
const {Visitor} = require('../parsers-primitives');
5256
const {buildComponentSchema} = require('./components');
5357
const {wrapComponentSchema} = require('../schema.js');
54-
const {buildModuleSchema} = require('../parsers-commons.js');
5558

5659
const fs = require('fs');
5760

@@ -402,36 +405,16 @@ class FlowParser implements Parser {
402405
break;
403406
}
404407

405-
const resolvedTypeAnnotation = types[node.id.name];
408+
const typeAnnotationName = this.nameForGenericTypeAnnotation(node);
409+
const resolvedTypeAnnotation = types[typeAnnotationName];
406410
if (resolvedTypeAnnotation == null) {
407411
break;
408412
}
409413

410-
switch (resolvedTypeAnnotation.type) {
411-
case parser.typeAlias: {
412-
typeResolutionStatus = {
413-
successful: true,
414-
type: 'alias',
415-
name: node.id.name,
416-
};
417-
node = resolvedTypeAnnotation.right;
418-
break;
419-
}
420-
case parser.enumDeclaration: {
421-
typeResolutionStatus = {
422-
successful: true,
423-
type: 'enum',
424-
name: node.id.name,
425-
};
426-
node = resolvedTypeAnnotation.body;
427-
break;
428-
}
429-
default: {
430-
throw new TypeError(
431-
`A non GenericTypeAnnotation must be a type declaration ('${parser.typeAlias}') or enum ('${parser.enumDeclaration}'). Instead, got the unsupported ${resolvedTypeAnnotation.type}.`,
432-
);
433-
}
434-
}
414+
const {typeAnnotation: typeAnnotationNode, typeResolutionStatus: status} =
415+
handleGenericTypeAnnotation(node, resolvedTypeAnnotation, this);
416+
typeResolutionStatus = status;
417+
node = typeAnnotationNode;
435418
}
436419

437420
return {

packages/react-native-codegen/src/parsers/parsers-commons.js

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@ import type {
3030

3131
import type {Parser} from './parser';
3232
import type {ParserType} from './errors';
33-
import type {ParserErrorCapturer, TypeDeclarationMap, PropAST} from './utils';
33+
import type {
34+
ParserErrorCapturer,
35+
TypeDeclarationMap,
36+
PropAST,
37+
TypeResolutionStatus,
38+
} from './utils';
3439
import type {ComponentSchemaBuilderConfig} from './schema.js';
3540

3641
const {
@@ -898,6 +903,79 @@ function getEventArgument(
898903
};
899904
}
900905

906+
function getTypeResolutionStatus(
907+
type: 'alias' | 'enum',
908+
typeAnnotation: $FlowFixMe,
909+
parser: Parser,
910+
): TypeResolutionStatus {
911+
return {
912+
successful: true,
913+
type,
914+
name: parser.nameForGenericTypeAnnotation(typeAnnotation),
915+
};
916+
}
917+
918+
function handleGenericTypeAnnotation(
919+
typeAnnotation: $FlowFixMe,
920+
resolvedTypeAnnotation: TypeDeclarationMap,
921+
parser: Parser,
922+
): {
923+
typeAnnotation: $FlowFixMe,
924+
typeResolutionStatus: TypeResolutionStatus,
925+
} {
926+
const parserType = parser.language();
927+
let typeResolutionStatus;
928+
let node;
929+
930+
switch (resolvedTypeAnnotation.type) {
931+
case parser.typeAlias: {
932+
typeResolutionStatus = getTypeResolutionStatus(
933+
'alias',
934+
typeAnnotation,
935+
parser,
936+
);
937+
node =
938+
parserType === 'Flow'
939+
? resolvedTypeAnnotation.right
940+
: resolvedTypeAnnotation.typeAnnotation;
941+
break;
942+
}
943+
case parser.enumDeclaration: {
944+
typeResolutionStatus = getTypeResolutionStatus(
945+
'enum',
946+
typeAnnotation,
947+
parser,
948+
);
949+
node =
950+
parserType === 'Flow'
951+
? resolvedTypeAnnotation.body
952+
: resolvedTypeAnnotation;
953+
break;
954+
}
955+
case 'TSInterfaceDeclaration': {
956+
typeResolutionStatus = getTypeResolutionStatus(
957+
'alias',
958+
typeAnnotation,
959+
parser,
960+
);
961+
node = resolvedTypeAnnotation;
962+
break;
963+
}
964+
default: {
965+
const errorMsg =
966+
parserType === 'Flow'
967+
? `A non GenericTypeAnnotation must be a type declaration ('${parser.typeAlias}') or enum ('${parser.enumDeclaration}'). Instead, got the unsupported ${resolvedTypeAnnotation.type}.`
968+
: `A non GenericTypeAnnotation must be a type declaration ('${parser.typeAlias}'), an interface ('${parser.interfaceDeclaration}'), or enum ('${parser.enumDeclaration}'). Instead, got the unsupported ${resolvedTypeAnnotation.type}.`;
969+
throw new TypeError(errorMsg);
970+
}
971+
}
972+
973+
return {
974+
typeAnnotation: node,
975+
typeResolutionStatus,
976+
};
977+
}
978+
901979
module.exports = {
902980
wrapModuleSchema,
903981
unwrapNullable,
@@ -920,4 +998,6 @@ module.exports = {
920998
extendsForProp,
921999
buildPropSchema,
9221000
getEventArgument,
1001+
handleGenericTypeAnnotation,
1002+
getTypeResolutionStatus,
9231003
};

packages/react-native-codegen/src/parsers/typescript/parser.js

Lines changed: 10 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ const {buildSchema} = require('../parsers-commons');
4545
const {Visitor} = require('../parsers-primitives');
4646
const {buildComponentSchema} = require('./components');
4747
const {wrapComponentSchema} = require('../schema.js');
48-
const {buildModuleSchema} = require('../parsers-commons.js');
48+
const {
49+
buildModuleSchema,
50+
handleGenericTypeAnnotation,
51+
} = require('../parsers-commons.js');
4952
const {parseTopLevelType} = require('./parseTopLevelType');
5053
const {
5154
getSchemaInfo,
@@ -400,45 +403,16 @@ class TypeScriptParser implements Parser {
400403
break;
401404
}
402405

403-
const resolvedTypeAnnotation = types[node.typeName.name];
406+
const typeAnnotationName = this.nameForGenericTypeAnnotation(node);
407+
const resolvedTypeAnnotation = types[typeAnnotationName];
404408
if (resolvedTypeAnnotation == null) {
405409
break;
406410
}
407411

408-
switch (resolvedTypeAnnotation.type) {
409-
case parser.typeAlias: {
410-
typeResolutionStatus = {
411-
successful: true,
412-
type: 'alias',
413-
name: node.typeName.name,
414-
};
415-
node = resolvedTypeAnnotation.typeAnnotation;
416-
break;
417-
}
418-
case parser.interfaceDeclaration: {
419-
typeResolutionStatus = {
420-
successful: true,
421-
type: 'alias',
422-
name: node.typeName.name,
423-
};
424-
node = resolvedTypeAnnotation;
425-
break;
426-
}
427-
case parser.enumDeclaration: {
428-
typeResolutionStatus = {
429-
successful: true,
430-
type: 'enum',
431-
name: node.typeName.name,
432-
};
433-
node = resolvedTypeAnnotation;
434-
break;
435-
}
436-
default: {
437-
throw new TypeError(
438-
`A non GenericTypeAnnotation must be a type declaration ('${parser.typeAlias}'), an interface ('${parser.interfaceDeclaration}'), or enum ('${parser.enumDeclaration}'). Instead, got the unsupported ${resolvedTypeAnnotation.type}.`,
439-
);
440-
}
441-
}
412+
const {typeAnnotation: typeAnnotationNode, typeResolutionStatus: status} =
413+
handleGenericTypeAnnotation(node, resolvedTypeAnnotation, this);
414+
typeResolutionStatus = status;
415+
node = typeAnnotationNode;
442416
}
443417

444418
return {

0 commit comments

Comments
 (0)