Skip to content

Commit e1f7cd1

Browse files
committed
extracted buildModuleSchema in parser-common.js
1 parent 3982a2c commit e1f7cd1

File tree

1 file changed

+239
-1
lines changed

1 file changed

+239
-1
lines changed

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

Lines changed: 239 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* LICENSE file in the root directory of this source tree.
66
*
77
* @format
8-
* @flow strict
8+
* @flow strict-local
99
*/
1010

1111
'use strict';
@@ -26,6 +26,63 @@ const {
2626
import type {ParserType} from './errors';
2727

2828
const invariant = require('invariant');
29+
const {
30+
getTypes,
31+
isModuleRegistryCall,
32+
resolveTypeAnnotation,
33+
} = require('./flow/utils');
34+
const {
35+
throwIfIncorrectModuleRegistryCallTypeParameterParserError,
36+
throwIfModuleInterfaceIsMisnamed,
37+
throwIfModuleInterfaceNotFound,
38+
throwIfModuleTypeIsUnsupported,
39+
throwIfMoreThanOneModuleInterfaceParserError,
40+
throwIfMoreThanOneModuleRegistryCalls,
41+
throwIfUnsupportedFunctionReturnTypeAnnotationParserError,
42+
throwIfUntypedModule,
43+
throwIfUnusedModuleInterfaceParserError,
44+
throwIfWrongNumberOfCallExpressionArgs,
45+
} = require('./error-utils');
46+
const {verifyPlatforms, visit} = require('./utils');
47+
const {
48+
IncorrectModuleRegistryCallArgumentTypeParserError,
49+
UnnamedFunctionParamParserError,
50+
UnsupportedFunctionParamTypeAnnotationParserError,
51+
} = require('./errors');
52+
import type {
53+
NamedShape,
54+
NativeModuleAliasMap,
55+
NativeModuleArrayTypeAnnotation,
56+
NativeModuleBaseTypeAnnotation,
57+
NativeModuleFunctionTypeAnnotation,
58+
NativeModuleParamTypeAnnotation,
59+
NativeModulePropertyShape,
60+
} from '../CodegenSchema';
61+
import type {ParserErrorCapturer, TypeDeclarationMap} from './utils';
62+
import {
63+
UnsupportedArrayElementTypeAnnotationParserError,
64+
UnsupportedEnumDeclarationParserError,
65+
UnsupportedGenericParserError,
66+
UnsupportedObjectPropertyTypeAnnotationParserError,
67+
UnsupportedTypeAnnotationParserError,
68+
} from './errors';
69+
import {
70+
emitBoolean,
71+
emitDouble,
72+
emitFunction,
73+
emitInt32,
74+
emitNumber,
75+
emitObject,
76+
emitPromise,
77+
emitRootTag,
78+
emitString,
79+
emitStringish,
80+
emitVoid,
81+
typeAliasResolution,
82+
} from './parsers-primitives';
83+
import {throwIfPropertyValueTypeIsUnsupported} from './error-utils';
84+
import {nullGuard} from './parsers-utils';
85+
import type {Parser} from './parser';
2986

3087
function wrapModuleSchema(
3188
nativeModuleSchema: NativeModuleSchema,
@@ -155,11 +212,192 @@ function emitUnionTypeAnnotation(
155212
});
156213
}
157214

215+
function buildModuleSchema(
216+
hasteModuleName: string,
217+
/**
218+
* TODO(T108222691): Use flow-types for @babel/parser
219+
*/
220+
ast: $FlowFixMe,
221+
tryParse: ParserErrorCapturer,
222+
language: ParserType,
223+
parser: Parser,
224+
): NativeModuleSchema {
225+
const types = getTypes(ast);
226+
227+
const moduleSpecs = (Object.values(types): $ReadOnlyArray<$FlowFixMe>).filter(
228+
//$FlowFixMe
229+
isModuleInterface,
230+
);
231+
232+
throwIfModuleInterfaceNotFound(
233+
moduleSpecs.length,
234+
hasteModuleName,
235+
ast,
236+
language,
237+
);
238+
239+
throwIfMoreThanOneModuleInterfaceParserError(
240+
hasteModuleName,
241+
moduleSpecs,
242+
language,
243+
);
244+
245+
const [moduleSpec] = moduleSpecs;
246+
247+
throwIfModuleInterfaceIsMisnamed(hasteModuleName, moduleSpec.id, language);
248+
249+
// Parse Module Names
250+
const moduleName = tryParse((): string => {
251+
const callExpressions = [];
252+
visit(ast, {
253+
CallExpression(node) {
254+
if (isModuleRegistryCall(node)) {
255+
callExpressions.push(node);
256+
}
257+
},
258+
});
259+
260+
throwIfUnusedModuleInterfaceParserError(
261+
hasteModuleName,
262+
moduleSpec,
263+
callExpressions,
264+
language,
265+
);
266+
267+
throwIfMoreThanOneModuleRegistryCalls(
268+
hasteModuleName,
269+
callExpressions,
270+
callExpressions.length,
271+
language,
272+
);
273+
274+
const [callExpression] = callExpressions;
275+
const typeParams =
276+
language === 'TypeScript'
277+
? callExpression.typeParameters
278+
: callExpression.typeArguments;
279+
const methodName = callExpression.callee.property.name;
280+
const callExpressionArgumentType =
281+
language === 'TypeScript' ? 'StringLiteral' : 'Literal';
282+
283+
throwIfWrongNumberOfCallExpressionArgs(
284+
hasteModuleName,
285+
callExpression,
286+
methodName,
287+
callExpression.arguments.length,
288+
language,
289+
);
290+
291+
if (callExpression.arguments[0].type !== callExpressionArgumentType) {
292+
const {type} = callExpression.arguments[0];
293+
throw new IncorrectModuleRegistryCallArgumentTypeParserError(
294+
hasteModuleName,
295+
callExpression.arguments[0],
296+
methodName,
297+
type,
298+
language,
299+
);
300+
}
301+
302+
const $moduleName = callExpression.arguments[0].value;
303+
304+
throwIfUntypedModule(
305+
typeParams,
306+
hasteModuleName,
307+
callExpression,
308+
methodName,
309+
$moduleName,
310+
language,
311+
);
312+
313+
throwIfIncorrectModuleRegistryCallTypeParameterParserError(
314+
hasteModuleName,
315+
typeParams,
316+
methodName,
317+
$moduleName,
318+
language,
319+
);
320+
321+
return $moduleName;
322+
});
323+
324+
const moduleNames = moduleName == null ? [] : [moduleName];
325+
326+
// Some module names use platform suffix to indicate platform-exclusive modules.
327+
// Eventually this should be made explicit in the Flow type itself.
328+
// Also check the hasteModuleName for platform suffix.
329+
// Note: this shape is consistent with ComponentSchema.
330+
const {cxxOnly, excludedPlatforms} = verifyPlatforms(
331+
hasteModuleName,
332+
moduleNames,
333+
);
334+
335+
let filteredModuleSpec;
336+
if (language === 'TypeScript') {
337+
filteredModuleSpec = moduleSpec.body.body.filter(
338+
property =>
339+
property.type === 'TSMethodSignature' ||
340+
property.type === 'TSPropertySignature',
341+
);
342+
} else {
343+
filteredModuleSpec = moduleSpec.body.properties.filter(
344+
property => property.type === 'ObjectTypeProperty',
345+
);
346+
}
347+
348+
// $FlowFixMe[missing-type-arg]
349+
return filteredModuleSpec
350+
.map<?{
351+
aliasMap: NativeModuleAliasMap,
352+
propertyShape: NativeModulePropertyShape,
353+
}>(property => {
354+
const aliasMap: {...NativeModuleAliasMap} = {};
355+
356+
return tryParse(() => ({
357+
aliasMap: aliasMap,
358+
// $FlowFixMe
359+
propertyShape: buildPropertySchema(
360+
hasteModuleName,
361+
property,
362+
types,
363+
aliasMap,
364+
tryParse,
365+
cxxOnly,
366+
language,
367+
parser,
368+
),
369+
}));
370+
})
371+
.filter(Boolean)
372+
.reduce(
373+
(moduleSchema: NativeModuleSchema, {aliasMap, propertyShape}) => {
374+
return {
375+
type: 'NativeModule',
376+
aliases: {...moduleSchema.aliases, ...aliasMap},
377+
spec: {
378+
properties: [...moduleSchema.spec.properties, propertyShape],
379+
},
380+
moduleNames: moduleSchema.moduleNames,
381+
excludedPlatforms: moduleSchema.excludedPlatforms,
382+
};
383+
},
384+
{
385+
type: 'NativeModule',
386+
aliases: {},
387+
spec: {properties: []},
388+
moduleNames: moduleNames,
389+
excludedPlatforms:
390+
excludedPlatforms.length !== 0 ? [...excludedPlatforms] : undefined,
391+
},
392+
);
393+
}
394+
158395
module.exports = {
159396
wrapModuleSchema,
160397
unwrapNullable,
161398
wrapNullable,
162399
assertGenericTypeAnnotationHasExactlyOneTypeParameter,
163400
emitMixedTypeAnnotation,
164401
emitUnionTypeAnnotation,
402+
buildModuleSchema,
165403
};

0 commit comments

Comments
 (0)