Skip to content

Commit c532fcf

Browse files
charlesbdudleyfacebook-github-bot
authored andcommitted
Copy Flow parser components logic to prepare TypeScript parser
Summary: These files are directly copied from the flow parser to aid in reviewing the next Diff, D33080623 Changelog: [Internal][Add] - Copy Flow parser component logic to aid in Diff review Reviewed By: RSNara Differential Revision: D33130222 fbshipit-source-id: ba7233b17d698793559da8b81bb7e1a78654e614
1 parent 114d5a8 commit c532fcf

File tree

7 files changed

+1287
-0
lines changed

7 files changed

+1287
-0
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
* @format
9+
*/
10+
11+
'use strict';
12+
13+
import type {
14+
NamedShape,
15+
CommandTypeAnnotation,
16+
} from '../../../CodegenSchema.js';
17+
import type {TypeDeclarationMap} from '../utils.js';
18+
19+
const {getValueFromTypes} = require('../utils.js');
20+
21+
type EventTypeAST = Object;
22+
23+
function buildCommandSchema(property: EventTypeAST, types: TypeDeclarationMap) {
24+
const name = property.key.name;
25+
const optional = property.optional;
26+
const value = getValueFromTypes(property.value, types);
27+
28+
const firstParam = value.params[0].typeAnnotation;
29+
30+
if (
31+
!(
32+
firstParam.id != null &&
33+
firstParam.id.type === 'QualifiedTypeIdentifier' &&
34+
firstParam.id.qualification.name === 'React' &&
35+
firstParam.id.id.name === 'ElementRef'
36+
)
37+
) {
38+
throw new Error(
39+
`The first argument of method ${name} must be of type React.ElementRef<>`,
40+
);
41+
}
42+
43+
const params = value.params.slice(1).map(param => {
44+
const paramName = param.name.name;
45+
const paramValue = getValueFromTypes(param.typeAnnotation, types);
46+
const type =
47+
paramValue.type === 'GenericTypeAnnotation'
48+
? paramValue.id.name
49+
: paramValue.type;
50+
let returnType;
51+
52+
switch (type) {
53+
case 'RootTag':
54+
returnType = {
55+
type: 'ReservedTypeAnnotation',
56+
name: 'RootTag',
57+
};
58+
break;
59+
case 'BooleanTypeAnnotation':
60+
returnType = {
61+
type: 'BooleanTypeAnnotation',
62+
};
63+
break;
64+
case 'Int32':
65+
returnType = {
66+
type: 'Int32TypeAnnotation',
67+
};
68+
break;
69+
case 'Double':
70+
returnType = {
71+
type: 'DoubleTypeAnnotation',
72+
};
73+
break;
74+
case 'Float':
75+
returnType = {
76+
type: 'FloatTypeAnnotation',
77+
};
78+
break;
79+
case 'StringTypeAnnotation':
80+
returnType = {
81+
type: 'StringTypeAnnotation',
82+
};
83+
break;
84+
default:
85+
(type: empty);
86+
throw new Error(
87+
`Unsupported param type for method "${name}", param "${paramName}". Found ${type}`,
88+
);
89+
}
90+
91+
return {
92+
name: paramName,
93+
typeAnnotation: returnType,
94+
};
95+
});
96+
97+
return {
98+
name,
99+
optional,
100+
typeAnnotation: {
101+
type: 'FunctionTypeAnnotation',
102+
params,
103+
returnTypeAnnotation: {
104+
type: 'VoidTypeAnnotation',
105+
},
106+
},
107+
};
108+
}
109+
110+
function getCommands(
111+
commandTypeAST: $ReadOnlyArray<EventTypeAST>,
112+
types: TypeDeclarationMap,
113+
): $ReadOnlyArray<NamedShape<CommandTypeAnnotation>> {
114+
return commandTypeAST
115+
.filter(property => property.type === 'ObjectTypeProperty')
116+
.map(property => buildCommandSchema(property, types))
117+
.filter(Boolean);
118+
}
119+
120+
module.exports = {
121+
getCommands,
122+
};
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow strict-local
8+
* @format
9+
*/
10+
11+
'use strict';
12+
13+
import type {
14+
EventTypeShape,
15+
NamedShape,
16+
EventTypeAnnotation,
17+
} from '../../../CodegenSchema.js';
18+
19+
function getPropertyType(
20+
name,
21+
optional,
22+
typeAnnotation,
23+
): NamedShape<EventTypeAnnotation> {
24+
const type =
25+
typeAnnotation.type === 'GenericTypeAnnotation'
26+
? typeAnnotation.id.name
27+
: typeAnnotation.type;
28+
29+
switch (type) {
30+
case 'BooleanTypeAnnotation':
31+
return {
32+
name,
33+
optional,
34+
typeAnnotation: {
35+
type: 'BooleanTypeAnnotation',
36+
},
37+
};
38+
case 'StringTypeAnnotation':
39+
return {
40+
name,
41+
optional,
42+
typeAnnotation: {
43+
type: 'StringTypeAnnotation',
44+
},
45+
};
46+
case 'Int32':
47+
return {
48+
name,
49+
optional,
50+
typeAnnotation: {
51+
type: 'Int32TypeAnnotation',
52+
},
53+
};
54+
case 'Double':
55+
return {
56+
name,
57+
optional,
58+
typeAnnotation: {
59+
type: 'DoubleTypeAnnotation',
60+
},
61+
};
62+
case 'Float':
63+
return {
64+
name,
65+
optional,
66+
typeAnnotation: {
67+
type: 'FloatTypeAnnotation',
68+
},
69+
};
70+
case '$ReadOnly':
71+
return getPropertyType(
72+
name,
73+
optional,
74+
typeAnnotation.typeParameters.params[0],
75+
);
76+
case 'ObjectTypeAnnotation':
77+
return {
78+
name,
79+
optional,
80+
typeAnnotation: {
81+
type: 'ObjectTypeAnnotation',
82+
properties: typeAnnotation.properties.map(buildPropertiesForEvent),
83+
},
84+
};
85+
case 'UnionTypeAnnotation':
86+
return {
87+
name,
88+
optional,
89+
typeAnnotation: {
90+
type: 'StringEnumTypeAnnotation',
91+
options: typeAnnotation.types.map(option => option.value),
92+
},
93+
};
94+
default:
95+
(type: empty);
96+
throw new Error(`Unable to determine event type for "${name}": ${type}`);
97+
}
98+
}
99+
100+
function findEventArgumentsAndType(
101+
typeAnnotation,
102+
types,
103+
bubblingType,
104+
paperName,
105+
) {
106+
if (!typeAnnotation.id) {
107+
throw new Error("typeAnnotation of event doesn't have a name");
108+
}
109+
const name = typeAnnotation.id.name;
110+
if (name === '$ReadOnly') {
111+
return {
112+
argumentProps: typeAnnotation.typeParameters.params[0].properties,
113+
paperTopLevelNameDeprecated: paperName,
114+
bubblingType,
115+
};
116+
} else if (name === 'BubblingEventHandler' || name === 'DirectEventHandler') {
117+
const eventType = name === 'BubblingEventHandler' ? 'bubble' : 'direct';
118+
const paperTopLevelNameDeprecated =
119+
typeAnnotation.typeParameters.params.length > 1
120+
? typeAnnotation.typeParameters.params[1].value
121+
: null;
122+
if (
123+
typeAnnotation.typeParameters.params[0].type ===
124+
'NullLiteralTypeAnnotation'
125+
) {
126+
return {
127+
argumentProps: [],
128+
bubblingType: eventType,
129+
paperTopLevelNameDeprecated,
130+
};
131+
}
132+
return findEventArgumentsAndType(
133+
typeAnnotation.typeParameters.params[0],
134+
types,
135+
eventType,
136+
paperTopLevelNameDeprecated,
137+
);
138+
} else if (types[name]) {
139+
return findEventArgumentsAndType(
140+
types[name].right,
141+
types,
142+
bubblingType,
143+
paperName,
144+
);
145+
} else {
146+
return {
147+
argumentProps: null,
148+
bubblingType: null,
149+
paperTopLevelNameDeprecated: null,
150+
};
151+
}
152+
}
153+
154+
function buildPropertiesForEvent(property): NamedShape<EventTypeAnnotation> {
155+
const name = property.key.name;
156+
const optional =
157+
property.value.type === 'NullableTypeAnnotation' || property.optional;
158+
let typeAnnotation =
159+
property.value.type === 'NullableTypeAnnotation'
160+
? property.value.typeAnnotation
161+
: property.value;
162+
163+
return getPropertyType(name, optional, typeAnnotation);
164+
}
165+
166+
function getEventArgument(argumentProps, name) {
167+
return {
168+
type: 'ObjectTypeAnnotation',
169+
properties: argumentProps.map(buildPropertiesForEvent),
170+
};
171+
}
172+
173+
function buildEventSchema(
174+
types: TypeMap,
175+
property: EventTypeAST,
176+
): ?EventTypeShape {
177+
const name = property.key.name;
178+
const optional =
179+
property.optional || property.value.type === 'NullableTypeAnnotation';
180+
181+
let typeAnnotation =
182+
property.value.type === 'NullableTypeAnnotation'
183+
? property.value.typeAnnotation
184+
: property.value;
185+
186+
if (
187+
typeAnnotation.type !== 'GenericTypeAnnotation' ||
188+
(typeAnnotation.id.name !== 'BubblingEventHandler' &&
189+
typeAnnotation.id.name !== 'DirectEventHandler')
190+
) {
191+
return null;
192+
}
193+
194+
const {argumentProps, bubblingType, paperTopLevelNameDeprecated} =
195+
findEventArgumentsAndType(typeAnnotation, types);
196+
197+
if (bubblingType && argumentProps) {
198+
if (paperTopLevelNameDeprecated != null) {
199+
return {
200+
name,
201+
optional,
202+
bubblingType,
203+
paperTopLevelNameDeprecated,
204+
typeAnnotation: {
205+
type: 'EventTypeAnnotation',
206+
argument: getEventArgument(argumentProps, name),
207+
},
208+
};
209+
}
210+
211+
return {
212+
name,
213+
optional,
214+
bubblingType,
215+
typeAnnotation: {
216+
type: 'EventTypeAnnotation',
217+
argument: getEventArgument(argumentProps, name),
218+
},
219+
};
220+
}
221+
222+
if (argumentProps === null) {
223+
throw new Error(`Unable to determine event arguments for "${name}"`);
224+
}
225+
226+
if (bubblingType === null) {
227+
throw new Error(`Unable to determine event arguments for "${name}"`);
228+
}
229+
}
230+
231+
// $FlowFixMe[unclear-type] there's no flowtype for ASTs
232+
type EventTypeAST = Object;
233+
234+
type TypeMap = {
235+
// $FlowFixMe[unclear-type] there's no flowtype for ASTs
236+
[string]: Object,
237+
...
238+
};
239+
240+
function getEvents(
241+
eventTypeAST: $ReadOnlyArray<EventTypeAST>,
242+
types: TypeMap,
243+
): $ReadOnlyArray<EventTypeShape> {
244+
return eventTypeAST
245+
.filter(property => property.type === 'ObjectTypeProperty')
246+
.map(property => buildEventSchema(types, property))
247+
.filter(Boolean);
248+
}
249+
250+
module.exports = {
251+
getEvents,
252+
};

0 commit comments

Comments
 (0)