Skip to content

Commit 5de24f4

Browse files
committed
codegen: add handleGenericTypeAnnotation in parser-commons
1 parent 3a7555f commit 5de24f4

File tree

6 files changed

+264
-65
lines changed

6 files changed

+264
-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+
parser.genericTypeAnnotationErrorMessage(resolvedTypeAnnotation),
1662+
),
1663+
);
1664+
});
1665+
});

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

Lines changed: 23 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 {
@@ -445,6 +428,18 @@ class FlowParser implements Parser {
445428
return (typeAnnotation, types, parser) =>
446429
this.getResolvedTypeAnnotation(typeAnnotation, types, parser);
447430
}
431+
432+
nextNodeForTypeAlias(typeAnnotation: $FlowFixMe): $FlowFixMe {
433+
return typeAnnotation.right;
434+
}
435+
436+
nextNodeForEnum(typeAnnotation: $FlowFixMe): $FlowFixMe {
437+
return typeAnnotation.body;
438+
}
439+
440+
genericTypeAnnotationErrorMessage(typeAnnotation: $FlowFixMe): string {
441+
return `A non GenericTypeAnnotation must be a type declaration ('${this.typeAlias}') or enum ('${this.enumDeclaration}'). Instead, got the unsupported ${typeAnnotation.type}.`;
442+
}
448443
}
449444

450445
module.exports = {

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,4 +361,19 @@ export interface Parser {
361361
};
362362

363363
getResolveTypeAnnotationFN(): ResolveTypeAnnotationFN;
364+
365+
/**
366+
* Given a typeAlias, it returns the next node.
367+
*/
368+
nextNodeForTypeAlias(typeAnnotation: $FlowFixMe): $FlowFixMe;
369+
370+
/**
371+
* Given an enum Declaration, it returns the next node.
372+
*/
373+
nextNodeForEnum(typeAnnotation: $FlowFixMe): $FlowFixMe;
374+
375+
/**
376+
* Given a unsupported typeAnnotation, returns an error message.
377+
*/
378+
genericTypeAnnotationErrorMessage(typeAnnotation: $FlowFixMe): string;
364379
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,4 +368,16 @@ export class MockedParser implements Parser {
368368
typeResolutionStatus,
369369
};
370370
}
371+
372+
nextNodeForTypeAlias(typeAnnotation: $FlowFixMe): $FlowFixMe {
373+
return typeAnnotation.right;
374+
}
375+
376+
nextNodeForEnum(typeAnnotation: $FlowFixMe): $FlowFixMe {
377+
return typeAnnotation.body;
378+
}
379+
380+
genericTypeAnnotationErrorMessage(typeAnnotation: $FlowFixMe): string {
381+
return `A non GenericTypeAnnotation must be a type declaration ('${this.typeAlias}') or enum ('${this.enumDeclaration}'). Instead, got the unsupported ${typeAnnotation.type}.`;
382+
}
371383
}

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

Lines changed: 73 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,71 @@ 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+
let typeResolutionStatus;
927+
let node;
928+
929+
switch (resolvedTypeAnnotation.type) {
930+
case parser.typeAlias: {
931+
typeResolutionStatus = getTypeResolutionStatus(
932+
'alias',
933+
typeAnnotation,
934+
parser,
935+
);
936+
node = parser.nextNodeForTypeAlias(resolvedTypeAnnotation);
937+
break;
938+
}
939+
case parser.enumDeclaration: {
940+
typeResolutionStatus = getTypeResolutionStatus(
941+
'enum',
942+
typeAnnotation,
943+
parser,
944+
);
945+
node = parser.nextNodeForEnum(resolvedTypeAnnotation);
946+
break;
947+
}
948+
// parser.interfaceDeclaration is not used here because for flow it should fall through to default case and throw an error
949+
case 'TSInterfaceDeclaration': {
950+
typeResolutionStatus = getTypeResolutionStatus(
951+
'alias',
952+
typeAnnotation,
953+
parser,
954+
);
955+
node = resolvedTypeAnnotation;
956+
break;
957+
}
958+
default: {
959+
throw new TypeError(
960+
parser.genericTypeAnnotationErrorMessage(resolvedTypeAnnotation),
961+
);
962+
}
963+
}
964+
965+
return {
966+
typeAnnotation: node,
967+
typeResolutionStatus,
968+
};
969+
}
970+
901971
module.exports = {
902972
wrapModuleSchema,
903973
unwrapNullable,
@@ -920,4 +990,6 @@ module.exports = {
920990
extendsForProp,
921991
buildPropSchema,
922992
getEventArgument,
993+
handleGenericTypeAnnotation,
994+
getTypeResolutionStatus,
923995
};

0 commit comments

Comments
 (0)