You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
791 lines
23 KiB
791 lines
23 KiB
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
*
|
|
* @format
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
function ownKeys(object, enumerableOnly) {
|
|
var keys = Object.keys(object);
|
|
if (Object.getOwnPropertySymbols) {
|
|
var symbols = Object.getOwnPropertySymbols(object);
|
|
enumerableOnly &&
|
|
(symbols = symbols.filter(function (sym) {
|
|
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
|
})),
|
|
keys.push.apply(keys, symbols);
|
|
}
|
|
return keys;
|
|
}
|
|
function _objectSpread(target) {
|
|
for (var i = 1; i < arguments.length; i++) {
|
|
var source = null != arguments[i] ? arguments[i] : {};
|
|
i % 2
|
|
? ownKeys(Object(source), !0).forEach(function (key) {
|
|
_defineProperty(target, key, source[key]);
|
|
})
|
|
: Object.getOwnPropertyDescriptors
|
|
? Object.defineProperties(
|
|
target,
|
|
Object.getOwnPropertyDescriptors(source),
|
|
)
|
|
: ownKeys(Object(source)).forEach(function (key) {
|
|
Object.defineProperty(
|
|
target,
|
|
key,
|
|
Object.getOwnPropertyDescriptor(source, key),
|
|
);
|
|
});
|
|
}
|
|
return target;
|
|
}
|
|
function _defineProperty(obj, key, value) {
|
|
key = _toPropertyKey(key);
|
|
if (key in obj) {
|
|
Object.defineProperty(obj, key, {
|
|
value: value,
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
});
|
|
} else {
|
|
obj[key] = value;
|
|
}
|
|
return obj;
|
|
}
|
|
function _toPropertyKey(arg) {
|
|
var key = _toPrimitive(arg, 'string');
|
|
return typeof key === 'symbol' ? key : String(key);
|
|
}
|
|
function _toPrimitive(input, hint) {
|
|
if (typeof input !== 'object' || input === null) return input;
|
|
var prim = input[Symbol.toPrimitive];
|
|
if (prim !== undefined) {
|
|
var res = prim.call(input, hint || 'default');
|
|
if (typeof res !== 'object') return res;
|
|
throw new TypeError('@@toPrimitive must return a primitive value.');
|
|
}
|
|
return (hint === 'string' ? String : Number)(input);
|
|
}
|
|
function _slicedToArray(arr, i) {
|
|
return (
|
|
_arrayWithHoles(arr) ||
|
|
_iterableToArrayLimit(arr, i) ||
|
|
_unsupportedIterableToArray(arr, i) ||
|
|
_nonIterableRest()
|
|
);
|
|
}
|
|
function _nonIterableRest() {
|
|
throw new TypeError(
|
|
'Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.',
|
|
);
|
|
}
|
|
function _unsupportedIterableToArray(o, minLen) {
|
|
if (!o) return;
|
|
if (typeof o === 'string') return _arrayLikeToArray(o, minLen);
|
|
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
if (n === 'Object' && o.constructor) n = o.constructor.name;
|
|
if (n === 'Map' || n === 'Set') return Array.from(o);
|
|
if (n === 'Arguments' || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))
|
|
return _arrayLikeToArray(o, minLen);
|
|
}
|
|
function _arrayLikeToArray(arr, len) {
|
|
if (len == null || len > arr.length) len = arr.length;
|
|
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
|
|
return arr2;
|
|
}
|
|
function _iterableToArrayLimit(arr, i) {
|
|
var _i =
|
|
null == arr
|
|
? null
|
|
: ('undefined' != typeof Symbol && arr[Symbol.iterator]) ||
|
|
arr['@@iterator'];
|
|
if (null != _i) {
|
|
var _s,
|
|
_e,
|
|
_x,
|
|
_r,
|
|
_arr = [],
|
|
_n = !0,
|
|
_d = !1;
|
|
try {
|
|
if (((_x = (_i = _i.call(arr)).next), 0 === i)) {
|
|
if (Object(_i) !== _i) return;
|
|
_n = !1;
|
|
} else
|
|
for (
|
|
;
|
|
!(_n = (_s = _x.call(_i)).done) &&
|
|
(_arr.push(_s.value), _arr.length !== i);
|
|
_n = !0
|
|
);
|
|
} catch (err) {
|
|
(_d = !0), (_e = err);
|
|
} finally {
|
|
try {
|
|
if (!_n && null != _i.return && ((_r = _i.return()), Object(_r) !== _r))
|
|
return;
|
|
} finally {
|
|
if (_d) throw _e;
|
|
}
|
|
}
|
|
return _arr;
|
|
}
|
|
}
|
|
function _arrayWithHoles(arr) {
|
|
if (Array.isArray(arr)) return arr;
|
|
}
|
|
const _require = require('../../parsers-utils'),
|
|
nullGuard = _require.nullGuard;
|
|
const _require2 = require('../../error-utils'),
|
|
throwIfMoreThanOneModuleRegistryCalls =
|
|
_require2.throwIfMoreThanOneModuleRegistryCalls;
|
|
const _require3 = require('../../utils'),
|
|
visit = _require3.visit,
|
|
isModuleRegistryCall = _require3.isModuleRegistryCall;
|
|
const _require4 = require('../utils.js'),
|
|
resolveTypeAnnotation = _require4.resolveTypeAnnotation,
|
|
getTypes = _require4.getTypes;
|
|
const _require5 = require('../../parsers-commons'),
|
|
unwrapNullable = _require5.unwrapNullable,
|
|
wrapNullable = _require5.wrapNullable,
|
|
assertGenericTypeAnnotationHasExactlyOneTypeParameter =
|
|
_require5.assertGenericTypeAnnotationHasExactlyOneTypeParameter,
|
|
emitMixedTypeAnnotation = _require5.emitMixedTypeAnnotation,
|
|
emitUnionTypeAnnotation = _require5.emitUnionTypeAnnotation,
|
|
translateDefault = _require5.translateDefault;
|
|
const _require6 = require('../../parsers-primitives'),
|
|
emitBoolean = _require6.emitBoolean,
|
|
emitDouble = _require6.emitDouble,
|
|
emitFloat = _require6.emitFloat,
|
|
emitFunction = _require6.emitFunction,
|
|
emitNumber = _require6.emitNumber,
|
|
emitInt32 = _require6.emitInt32,
|
|
emitObject = _require6.emitObject,
|
|
emitPromise = _require6.emitPromise,
|
|
emitRootTag = _require6.emitRootTag,
|
|
emitVoid = _require6.emitVoid,
|
|
emitString = _require6.emitString,
|
|
emitStringish = _require6.emitStringish,
|
|
typeAliasResolution = _require6.typeAliasResolution;
|
|
const _require7 = require('../../errors.js'),
|
|
UnnamedFunctionParamParserError = _require7.UnnamedFunctionParamParserError,
|
|
UnsupportedArrayElementTypeAnnotationParserError =
|
|
_require7.UnsupportedArrayElementTypeAnnotationParserError,
|
|
UnsupportedTypeAnnotationParserError =
|
|
_require7.UnsupportedTypeAnnotationParserError,
|
|
UnsupportedObjectPropertyTypeAnnotationParserError =
|
|
_require7.UnsupportedObjectPropertyTypeAnnotationParserError,
|
|
IncorrectModuleRegistryCallArgumentTypeParserError =
|
|
_require7.IncorrectModuleRegistryCallArgumentTypeParserError;
|
|
const _require8 = require('../../utils'),
|
|
verifyPlatforms = _require8.verifyPlatforms;
|
|
const _require9 = require('../../error-utils'),
|
|
throwIfUnsupportedFunctionReturnTypeAnnotationParserError =
|
|
_require9.throwIfUnsupportedFunctionReturnTypeAnnotationParserError,
|
|
throwIfModuleInterfaceNotFound = _require9.throwIfModuleInterfaceNotFound,
|
|
throwIfModuleInterfaceIsMisnamed = _require9.throwIfModuleInterfaceIsMisnamed,
|
|
throwIfPropertyValueTypeIsUnsupported =
|
|
_require9.throwIfPropertyValueTypeIsUnsupported,
|
|
throwIfUnusedModuleInterfaceParserError =
|
|
_require9.throwIfUnusedModuleInterfaceParserError,
|
|
throwIfWrongNumberOfCallExpressionArgs =
|
|
_require9.throwIfWrongNumberOfCallExpressionArgs,
|
|
throwIfIncorrectModuleRegistryCallTypeParameterParserError =
|
|
_require9.throwIfIncorrectModuleRegistryCallTypeParameterParserError,
|
|
throwIfUntypedModule = _require9.throwIfUntypedModule,
|
|
throwIfModuleTypeIsUnsupported = _require9.throwIfModuleTypeIsUnsupported,
|
|
throwIfMoreThanOneModuleInterfaceParserError =
|
|
_require9.throwIfMoreThanOneModuleInterfaceParserError,
|
|
throwIfUnsupportedFunctionParamTypeAnnotationParserError =
|
|
_require9.throwIfUnsupportedFunctionParamTypeAnnotationParserError;
|
|
const _require10 = require('../parser.js'),
|
|
FlowParser = _require10.FlowParser;
|
|
const _require11 = require('../../parsers-commons'),
|
|
getKeyName = _require11.getKeyName;
|
|
const language = 'Flow';
|
|
const parser = new FlowParser();
|
|
function translateArrayTypeAnnotation(
|
|
hasteModuleName,
|
|
types,
|
|
aliasMap,
|
|
cxxOnly,
|
|
flowArrayType,
|
|
flowElementType,
|
|
nullable,
|
|
) {
|
|
try {
|
|
/**
|
|
* TODO(T72031674): Migrate all our NativeModule specs to not use
|
|
* invalid Array ElementTypes. Then, make the elementType a required
|
|
* parameter.
|
|
*/
|
|
const _unwrapNullable = unwrapNullable(
|
|
translateTypeAnnotation(
|
|
hasteModuleName,
|
|
flowElementType,
|
|
types,
|
|
aliasMap,
|
|
/**
|
|
* TODO(T72031674): Ensure that all ParsingErrors that are thrown
|
|
* while parsing the array element don't get captured and collected.
|
|
* Why? If we detect any parsing error while parsing the element,
|
|
* we should default it to null down the line, here. This is
|
|
* the correct behaviour until we migrate all our NativeModule specs
|
|
* to be parseable.
|
|
*/
|
|
nullGuard,
|
|
cxxOnly,
|
|
),
|
|
),
|
|
_unwrapNullable2 = _slicedToArray(_unwrapNullable, 2),
|
|
elementType = _unwrapNullable2[0],
|
|
isElementTypeNullable = _unwrapNullable2[1];
|
|
if (elementType.type === 'VoidTypeAnnotation') {
|
|
throw new UnsupportedArrayElementTypeAnnotationParserError(
|
|
hasteModuleName,
|
|
flowElementType,
|
|
flowArrayType,
|
|
'void',
|
|
language,
|
|
);
|
|
}
|
|
if (elementType.type === 'PromiseTypeAnnotation') {
|
|
throw new UnsupportedArrayElementTypeAnnotationParserError(
|
|
hasteModuleName,
|
|
flowElementType,
|
|
flowArrayType,
|
|
'Promise',
|
|
language,
|
|
);
|
|
}
|
|
if (elementType.type === 'FunctionTypeAnnotation') {
|
|
throw new UnsupportedArrayElementTypeAnnotationParserError(
|
|
hasteModuleName,
|
|
flowElementType,
|
|
flowArrayType,
|
|
'FunctionTypeAnnotation',
|
|
language,
|
|
);
|
|
}
|
|
const finalTypeAnnotation = {
|
|
type: 'ArrayTypeAnnotation',
|
|
elementType: wrapNullable(isElementTypeNullable, elementType),
|
|
};
|
|
return wrapNullable(nullable, finalTypeAnnotation);
|
|
} catch (ex) {
|
|
return wrapNullable(nullable, {
|
|
type: 'ArrayTypeAnnotation',
|
|
});
|
|
}
|
|
}
|
|
function translateTypeAnnotation(
|
|
hasteModuleName,
|
|
/**
|
|
* TODO(T71778680): Flow-type this node.
|
|
*/
|
|
flowTypeAnnotation,
|
|
types,
|
|
aliasMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
) {
|
|
const _resolveTypeAnnotatio = resolveTypeAnnotation(
|
|
flowTypeAnnotation,
|
|
types,
|
|
),
|
|
nullable = _resolveTypeAnnotatio.nullable,
|
|
typeAnnotation = _resolveTypeAnnotatio.typeAnnotation,
|
|
typeAliasResolutionStatus = _resolveTypeAnnotatio.typeAliasResolutionStatus;
|
|
switch (typeAnnotation.type) {
|
|
case 'GenericTypeAnnotation': {
|
|
switch (typeAnnotation.id.name) {
|
|
case 'RootTag': {
|
|
return emitRootTag(nullable);
|
|
}
|
|
case 'Promise': {
|
|
return emitPromise(
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
language,
|
|
nullable,
|
|
);
|
|
}
|
|
case 'Array':
|
|
case '$ReadOnlyArray': {
|
|
assertGenericTypeAnnotationHasExactlyOneTypeParameter(
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
language,
|
|
);
|
|
return translateArrayTypeAnnotation(
|
|
hasteModuleName,
|
|
types,
|
|
aliasMap,
|
|
cxxOnly,
|
|
typeAnnotation.type,
|
|
typeAnnotation.typeParameters.params[0],
|
|
nullable,
|
|
);
|
|
}
|
|
case '$ReadOnly': {
|
|
assertGenericTypeAnnotationHasExactlyOneTypeParameter(
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
language,
|
|
);
|
|
const _unwrapNullable3 = unwrapNullable(
|
|
translateTypeAnnotation(
|
|
hasteModuleName,
|
|
typeAnnotation.typeParameters.params[0],
|
|
types,
|
|
aliasMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
),
|
|
),
|
|
_unwrapNullable4 = _slicedToArray(_unwrapNullable3, 2),
|
|
paramType = _unwrapNullable4[0],
|
|
isParamNullable = _unwrapNullable4[1];
|
|
return wrapNullable(nullable || isParamNullable, paramType);
|
|
}
|
|
case 'Stringish': {
|
|
return emitStringish(nullable);
|
|
}
|
|
case 'Int32': {
|
|
return emitInt32(nullable);
|
|
}
|
|
case 'Double': {
|
|
return emitDouble(nullable);
|
|
}
|
|
case 'Float': {
|
|
return emitFloat(nullable);
|
|
}
|
|
case 'UnsafeObject':
|
|
case 'Object': {
|
|
return emitObject(nullable);
|
|
}
|
|
default: {
|
|
return translateDefault(
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
types,
|
|
nullable,
|
|
parser,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
case 'ObjectTypeAnnotation': {
|
|
const objectTypeAnnotation = {
|
|
type: 'ObjectTypeAnnotation',
|
|
// $FlowFixMe[missing-type-arg]
|
|
properties: [...typeAnnotation.properties, ...typeAnnotation.indexers]
|
|
.map(property => {
|
|
return tryParse(() => {
|
|
if (
|
|
property.type !== 'ObjectTypeProperty' &&
|
|
property.type !== 'ObjectTypeIndexer'
|
|
) {
|
|
throw new UnsupportedObjectPropertyTypeAnnotationParserError(
|
|
hasteModuleName,
|
|
property,
|
|
property.type,
|
|
language,
|
|
);
|
|
}
|
|
const _property$optional = property.optional,
|
|
optional =
|
|
_property$optional === void 0 ? false : _property$optional;
|
|
const name = getKeyName(property, hasteModuleName, language);
|
|
if (property.type === 'ObjectTypeIndexer') {
|
|
return {
|
|
name,
|
|
optional,
|
|
typeAnnotation: emitObject(nullable),
|
|
};
|
|
}
|
|
const _unwrapNullable5 = unwrapNullable(
|
|
translateTypeAnnotation(
|
|
hasteModuleName,
|
|
property.value,
|
|
types,
|
|
aliasMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
),
|
|
),
|
|
_unwrapNullable6 = _slicedToArray(_unwrapNullable5, 2),
|
|
propertyTypeAnnotation = _unwrapNullable6[0],
|
|
isPropertyNullable = _unwrapNullable6[1];
|
|
if (
|
|
propertyTypeAnnotation.type === 'FunctionTypeAnnotation' ||
|
|
propertyTypeAnnotation.type === 'PromiseTypeAnnotation' ||
|
|
propertyTypeAnnotation.type === 'VoidTypeAnnotation'
|
|
) {
|
|
throwIfPropertyValueTypeIsUnsupported(
|
|
hasteModuleName,
|
|
property.value,
|
|
property.key,
|
|
propertyTypeAnnotation.type,
|
|
language,
|
|
);
|
|
} else {
|
|
return {
|
|
name,
|
|
optional,
|
|
typeAnnotation: wrapNullable(
|
|
isPropertyNullable,
|
|
propertyTypeAnnotation,
|
|
),
|
|
};
|
|
}
|
|
});
|
|
})
|
|
.filter(Boolean),
|
|
};
|
|
return typeAliasResolution(
|
|
typeAliasResolutionStatus,
|
|
objectTypeAnnotation,
|
|
aliasMap,
|
|
nullable,
|
|
);
|
|
}
|
|
case 'BooleanTypeAnnotation': {
|
|
return emitBoolean(nullable);
|
|
}
|
|
case 'NumberTypeAnnotation': {
|
|
return emitNumber(nullable);
|
|
}
|
|
case 'VoidTypeAnnotation': {
|
|
return emitVoid(nullable);
|
|
}
|
|
case 'StringTypeAnnotation': {
|
|
return emitString(nullable);
|
|
}
|
|
case 'FunctionTypeAnnotation': {
|
|
const translateFunctionTypeAnnotationValue =
|
|
translateFunctionTypeAnnotation(
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
types,
|
|
aliasMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
);
|
|
return emitFunction(nullable, translateFunctionTypeAnnotationValue);
|
|
}
|
|
case 'UnionTypeAnnotation': {
|
|
if (cxxOnly) {
|
|
return emitUnionTypeAnnotation(
|
|
nullable,
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
language,
|
|
);
|
|
}
|
|
// Fallthrough
|
|
}
|
|
|
|
case 'MixedTypeAnnotation': {
|
|
if (cxxOnly) {
|
|
return emitMixedTypeAnnotation(nullable);
|
|
}
|
|
// Fallthrough
|
|
}
|
|
|
|
default: {
|
|
throw new UnsupportedTypeAnnotationParserError(
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
language,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
function translateFunctionTypeAnnotation(
|
|
hasteModuleName,
|
|
// TODO(T71778680): This is a FunctionTypeAnnotation. Type this.
|
|
flowFunctionTypeAnnotation,
|
|
types,
|
|
aliasMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
) {
|
|
const params = [];
|
|
for (const flowParam of flowFunctionTypeAnnotation.params) {
|
|
const parsedParam = tryParse(() => {
|
|
if (flowParam.name == null) {
|
|
throw new UnnamedFunctionParamParserError(
|
|
flowParam,
|
|
hasteModuleName,
|
|
language,
|
|
);
|
|
}
|
|
const paramName = flowParam.name.name;
|
|
const _unwrapNullable7 = unwrapNullable(
|
|
translateTypeAnnotation(
|
|
hasteModuleName,
|
|
flowParam.typeAnnotation,
|
|
types,
|
|
aliasMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
),
|
|
),
|
|
_unwrapNullable8 = _slicedToArray(_unwrapNullable7, 2),
|
|
paramTypeAnnotation = _unwrapNullable8[0],
|
|
isParamTypeAnnotationNullable = _unwrapNullable8[1];
|
|
if (
|
|
paramTypeAnnotation.type === 'VoidTypeAnnotation' ||
|
|
paramTypeAnnotation.type === 'PromiseTypeAnnotation'
|
|
) {
|
|
return throwIfUnsupportedFunctionParamTypeAnnotationParserError(
|
|
hasteModuleName,
|
|
flowParam.typeAnnotation,
|
|
paramName,
|
|
paramTypeAnnotation.type,
|
|
);
|
|
}
|
|
return {
|
|
name: flowParam.name.name,
|
|
optional: flowParam.optional,
|
|
typeAnnotation: wrapNullable(
|
|
isParamTypeAnnotationNullable,
|
|
paramTypeAnnotation,
|
|
),
|
|
};
|
|
});
|
|
if (parsedParam != null) {
|
|
params.push(parsedParam);
|
|
}
|
|
}
|
|
const _unwrapNullable9 = unwrapNullable(
|
|
translateTypeAnnotation(
|
|
hasteModuleName,
|
|
flowFunctionTypeAnnotation.returnType,
|
|
types,
|
|
aliasMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
),
|
|
),
|
|
_unwrapNullable10 = _slicedToArray(_unwrapNullable9, 2),
|
|
returnTypeAnnotation = _unwrapNullable10[0],
|
|
isReturnTypeAnnotationNullable = _unwrapNullable10[1];
|
|
throwIfUnsupportedFunctionReturnTypeAnnotationParserError(
|
|
hasteModuleName,
|
|
flowFunctionTypeAnnotation,
|
|
'FunctionTypeAnnotation',
|
|
language,
|
|
cxxOnly,
|
|
returnTypeAnnotation.type,
|
|
);
|
|
return {
|
|
type: 'FunctionTypeAnnotation',
|
|
returnTypeAnnotation: wrapNullable(
|
|
isReturnTypeAnnotationNullable,
|
|
returnTypeAnnotation,
|
|
),
|
|
params,
|
|
};
|
|
}
|
|
function buildPropertySchema(
|
|
hasteModuleName,
|
|
// TODO(T71778680): This is an ObjectTypeProperty containing either:
|
|
// - a FunctionTypeAnnotation or GenericTypeAnnotation
|
|
// - a NullableTypeAnnoation containing a FunctionTypeAnnotation or GenericTypeAnnotation
|
|
// Flow type this node
|
|
property,
|
|
types,
|
|
aliasMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
) {
|
|
let nullable = false;
|
|
let key = property.key,
|
|
value = property.value;
|
|
const methodName = key.name;
|
|
var _resolveTypeAnnotatio2 = resolveTypeAnnotation(value, types);
|
|
nullable = _resolveTypeAnnotatio2.nullable;
|
|
value = _resolveTypeAnnotatio2.typeAnnotation;
|
|
throwIfModuleTypeIsUnsupported(
|
|
hasteModuleName,
|
|
property.value,
|
|
property.key.name,
|
|
value.type,
|
|
language,
|
|
);
|
|
return {
|
|
name: methodName,
|
|
optional: property.optional,
|
|
typeAnnotation: wrapNullable(
|
|
nullable,
|
|
translateFunctionTypeAnnotation(
|
|
hasteModuleName,
|
|
value,
|
|
types,
|
|
aliasMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
),
|
|
),
|
|
};
|
|
}
|
|
function isModuleInterface(node) {
|
|
return (
|
|
node.type === 'InterfaceDeclaration' &&
|
|
node.extends.length === 1 &&
|
|
node.extends[0].type === 'InterfaceExtends' &&
|
|
node.extends[0].id.name === 'TurboModule'
|
|
);
|
|
}
|
|
function buildModuleSchema(
|
|
hasteModuleName,
|
|
/**
|
|
* TODO(T71778680): Flow-type this node.
|
|
*/
|
|
ast,
|
|
tryParse,
|
|
) {
|
|
const types = getTypes(ast);
|
|
const moduleSpecs = Object.values(types).filter(isModuleInterface);
|
|
throwIfModuleInterfaceNotFound(
|
|
moduleSpecs.length,
|
|
hasteModuleName,
|
|
ast,
|
|
language,
|
|
);
|
|
throwIfMoreThanOneModuleInterfaceParserError(
|
|
hasteModuleName,
|
|
moduleSpecs,
|
|
language,
|
|
);
|
|
const _moduleSpecs = _slicedToArray(moduleSpecs, 1),
|
|
moduleSpec = _moduleSpecs[0];
|
|
throwIfModuleInterfaceIsMisnamed(hasteModuleName, moduleSpec.id, language);
|
|
|
|
// Parse Module Names
|
|
const moduleName = tryParse(() => {
|
|
const callExpressions = [];
|
|
visit(ast, {
|
|
CallExpression(node) {
|
|
if (isModuleRegistryCall(node)) {
|
|
callExpressions.push(node);
|
|
}
|
|
},
|
|
});
|
|
throwIfUnusedModuleInterfaceParserError(
|
|
hasteModuleName,
|
|
moduleSpec,
|
|
callExpressions,
|
|
language,
|
|
);
|
|
throwIfMoreThanOneModuleRegistryCalls(
|
|
hasteModuleName,
|
|
callExpressions,
|
|
callExpressions.length,
|
|
language,
|
|
);
|
|
const callExpression = callExpressions[0];
|
|
const typeArguments = callExpression.typeArguments;
|
|
const methodName = callExpression.callee.property.name;
|
|
throwIfWrongNumberOfCallExpressionArgs(
|
|
hasteModuleName,
|
|
callExpression,
|
|
methodName,
|
|
callExpression.arguments.length,
|
|
language,
|
|
);
|
|
if (callExpression.arguments[0].type !== 'Literal') {
|
|
const type = callExpression.arguments[0].type;
|
|
throw new IncorrectModuleRegistryCallArgumentTypeParserError(
|
|
hasteModuleName,
|
|
callExpression.arguments[0],
|
|
methodName,
|
|
type,
|
|
language,
|
|
);
|
|
}
|
|
const $moduleName = callExpression.arguments[0].value;
|
|
throwIfUntypedModule(
|
|
typeArguments,
|
|
hasteModuleName,
|
|
callExpression,
|
|
methodName,
|
|
$moduleName,
|
|
language,
|
|
);
|
|
throwIfIncorrectModuleRegistryCallTypeParameterParserError(
|
|
hasteModuleName,
|
|
typeArguments,
|
|
methodName,
|
|
$moduleName,
|
|
language,
|
|
);
|
|
return $moduleName;
|
|
});
|
|
const moduleNames = moduleName == null ? [] : [moduleName];
|
|
|
|
// Some module names use platform suffix to indicate platform-exclusive modules.
|
|
// Eventually this should be made explicit in the Flow type itself.
|
|
// Also check the hasteModuleName for platform suffix.
|
|
// Note: this shape is consistent with ComponentSchema.
|
|
const _verifyPlatforms = verifyPlatforms(hasteModuleName, moduleNames),
|
|
cxxOnly = _verifyPlatforms.cxxOnly,
|
|
excludedPlatforms = _verifyPlatforms.excludedPlatforms;
|
|
|
|
// $FlowFixMe[missing-type-arg]
|
|
return moduleSpec.body.properties
|
|
.filter(property => property.type === 'ObjectTypeProperty')
|
|
.map(property => {
|
|
const aliasMap = {};
|
|
return tryParse(() => ({
|
|
aliasMap: aliasMap,
|
|
propertyShape: buildPropertySchema(
|
|
hasteModuleName,
|
|
property,
|
|
types,
|
|
aliasMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
),
|
|
}));
|
|
})
|
|
.filter(Boolean)
|
|
.reduce(
|
|
(moduleSchema, {aliasMap, propertyShape}) => {
|
|
return {
|
|
type: 'NativeModule',
|
|
aliases: _objectSpread(
|
|
_objectSpread({}, moduleSchema.aliases),
|
|
aliasMap,
|
|
),
|
|
spec: {
|
|
properties: [...moduleSchema.spec.properties, propertyShape],
|
|
},
|
|
moduleNames: moduleSchema.moduleNames,
|
|
excludedPlatforms: moduleSchema.excludedPlatforms,
|
|
};
|
|
},
|
|
{
|
|
type: 'NativeModule',
|
|
aliases: {},
|
|
spec: {
|
|
properties: [],
|
|
},
|
|
moduleNames: moduleNames,
|
|
excludedPlatforms:
|
|
excludedPlatforms.length !== 0 ? [...excludedPlatforms] : undefined,
|
|
},
|
|
);
|
|
}
|
|
module.exports = {
|
|
buildModuleSchema,
|
|
};
|