1348 lines
38 KiB
JavaScript
1348 lines
38 KiB
JavaScript
/**
|
|
* 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(e, r) {
|
|
var t = Object.keys(e);
|
|
if (Object.getOwnPropertySymbols) {
|
|
var o = Object.getOwnPropertySymbols(e);
|
|
r &&
|
|
(o = o.filter(function (r) {
|
|
return Object.getOwnPropertyDescriptor(e, r).enumerable;
|
|
})),
|
|
t.push.apply(t, o);
|
|
}
|
|
return t;
|
|
}
|
|
function _objectSpread(e) {
|
|
for (var r = 1; r < arguments.length; r++) {
|
|
var t = null != arguments[r] ? arguments[r] : {};
|
|
r % 2
|
|
? ownKeys(Object(t), !0).forEach(function (r) {
|
|
_defineProperty(e, r, t[r]);
|
|
})
|
|
: Object.getOwnPropertyDescriptors
|
|
? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t))
|
|
: ownKeys(Object(t)).forEach(function (r) {
|
|
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
|
|
});
|
|
}
|
|
return e;
|
|
}
|
|
function _defineProperty(e, r, t) {
|
|
return (
|
|
(r = _toPropertyKey(r)) in e
|
|
? Object.defineProperty(e, r, {
|
|
value: t,
|
|
enumerable: !0,
|
|
configurable: !0,
|
|
writable: !0,
|
|
})
|
|
: (e[r] = t),
|
|
e
|
|
);
|
|
}
|
|
function _toPropertyKey(t) {
|
|
var i = _toPrimitive(t, 'string');
|
|
return 'symbol' == typeof i ? i : i + '';
|
|
}
|
|
function _toPrimitive(t, r) {
|
|
if ('object' != typeof t || !t) return t;
|
|
var e = t[Symbol.toPrimitive];
|
|
if (void 0 !== e) {
|
|
var i = e.call(t, r || 'default');
|
|
if ('object' != typeof i) return i;
|
|
throw new TypeError('@@toPrimitive must return a primitive value.');
|
|
}
|
|
return ('string' === r ? String : Number)(t);
|
|
}
|
|
function _slicedToArray(r, e) {
|
|
return (
|
|
_arrayWithHoles(r) ||
|
|
_iterableToArrayLimit(r, e) ||
|
|
_unsupportedIterableToArray(r, e) ||
|
|
_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(r, a) {
|
|
if (r) {
|
|
if ('string' == typeof r) return _arrayLikeToArray(r, a);
|
|
var t = {}.toString.call(r).slice(8, -1);
|
|
return (
|
|
'Object' === t && r.constructor && (t = r.constructor.name),
|
|
'Map' === t || 'Set' === t
|
|
? Array.from(r)
|
|
: 'Arguments' === t ||
|
|
/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)
|
|
? _arrayLikeToArray(r, a)
|
|
: void 0
|
|
);
|
|
}
|
|
}
|
|
function _arrayLikeToArray(r, a) {
|
|
(null == a || a > r.length) && (a = r.length);
|
|
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
|
|
return n;
|
|
}
|
|
function _iterableToArrayLimit(r, l) {
|
|
var t =
|
|
null == r
|
|
? null
|
|
: ('undefined' != typeof Symbol && r[Symbol.iterator]) || r['@@iterator'];
|
|
if (null != t) {
|
|
var e,
|
|
n,
|
|
i,
|
|
u,
|
|
a = [],
|
|
f = !0,
|
|
o = !1;
|
|
try {
|
|
if (((i = (t = t.call(r)).next), 0 === l)) {
|
|
if (Object(t) !== t) return;
|
|
f = !1;
|
|
} else
|
|
for (
|
|
;
|
|
!(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l);
|
|
f = !0
|
|
);
|
|
} catch (r) {
|
|
(o = !0), (n = r);
|
|
} finally {
|
|
try {
|
|
if (!f && null != t.return && ((u = t.return()), Object(u) !== u))
|
|
return;
|
|
} finally {
|
|
if (o) throw n;
|
|
}
|
|
}
|
|
return a;
|
|
}
|
|
}
|
|
function _arrayWithHoles(r) {
|
|
if (Array.isArray(r)) return r;
|
|
}
|
|
const _require = require('./error-utils'),
|
|
throwIfConfigNotfound = _require.throwIfConfigNotfound,
|
|
throwIfEventEmitterEventTypeIsUnsupported =
|
|
_require.throwIfEventEmitterEventTypeIsUnsupported,
|
|
throwIfEventEmitterTypeIsUnsupported =
|
|
_require.throwIfEventEmitterTypeIsUnsupported,
|
|
throwIfIncorrectModuleRegistryCallArgument =
|
|
_require.throwIfIncorrectModuleRegistryCallArgument,
|
|
throwIfIncorrectModuleRegistryCallTypeParameterParserError =
|
|
_require.throwIfIncorrectModuleRegistryCallTypeParameterParserError,
|
|
throwIfModuleInterfaceIsMisnamed = _require.throwIfModuleInterfaceIsMisnamed,
|
|
throwIfModuleInterfaceNotFound = _require.throwIfModuleInterfaceNotFound,
|
|
throwIfModuleTypeIsUnsupported = _require.throwIfModuleTypeIsUnsupported,
|
|
throwIfMoreThanOneCodegenNativecommands =
|
|
_require.throwIfMoreThanOneCodegenNativecommands,
|
|
throwIfMoreThanOneConfig = _require.throwIfMoreThanOneConfig,
|
|
throwIfMoreThanOneModuleInterfaceParserError =
|
|
_require.throwIfMoreThanOneModuleInterfaceParserError,
|
|
throwIfMoreThanOneModuleRegistryCalls =
|
|
_require.throwIfMoreThanOneModuleRegistryCalls,
|
|
throwIfPropertyValueTypeIsUnsupported =
|
|
_require.throwIfPropertyValueTypeIsUnsupported,
|
|
throwIfTypeAliasIsNotInterface = _require.throwIfTypeAliasIsNotInterface,
|
|
throwIfUnsupportedFunctionParamTypeAnnotationParserError =
|
|
_require.throwIfUnsupportedFunctionParamTypeAnnotationParserError,
|
|
throwIfUnsupportedFunctionReturnTypeAnnotationParserError =
|
|
_require.throwIfUnsupportedFunctionReturnTypeAnnotationParserError,
|
|
throwIfUntypedModule = _require.throwIfUntypedModule,
|
|
throwIfUnusedModuleInterfaceParserError =
|
|
_require.throwIfUnusedModuleInterfaceParserError,
|
|
throwIfWrongNumberOfCallExpressionArgs =
|
|
_require.throwIfWrongNumberOfCallExpressionArgs;
|
|
const _require2 = require('./errors'),
|
|
MissingTypeParameterGenericParserError =
|
|
_require2.MissingTypeParameterGenericParserError,
|
|
MoreThanOneTypeParameterGenericParserError =
|
|
_require2.MoreThanOneTypeParameterGenericParserError,
|
|
UnnamedFunctionParamParserError = _require2.UnnamedFunctionParamParserError,
|
|
UnsupportedObjectDirectRecursivePropertyParserError =
|
|
_require2.UnsupportedObjectDirectRecursivePropertyParserError;
|
|
const _require3 = require('./utils'),
|
|
createParserErrorCapturer = _require3.createParserErrorCapturer,
|
|
extractNativeModuleName = _require3.extractNativeModuleName,
|
|
getConfigType = _require3.getConfigType,
|
|
getSortedObject = _require3.getSortedObject,
|
|
isModuleRegistryCall = _require3.isModuleRegistryCall,
|
|
verifyPlatforms = _require3.verifyPlatforms,
|
|
visit = _require3.visit;
|
|
const invariant = require('invariant');
|
|
|
|
// $FlowFixMe[unclear-type] TODO(T108222691): Use flow-types for @babel/parser
|
|
|
|
function wrapModuleSchema(nativeModuleSchema, hasteModuleName) {
|
|
return {
|
|
modules: {
|
|
[hasteModuleName]: nativeModuleSchema,
|
|
},
|
|
};
|
|
}
|
|
|
|
// $FlowFixMe[unsupported-variance-annotation]
|
|
function unwrapNullable(x) {
|
|
if (x.type === 'NullableTypeAnnotation') {
|
|
return [x.typeAnnotation, true];
|
|
}
|
|
return [x, false];
|
|
}
|
|
|
|
// $FlowFixMe[unsupported-variance-annotation]
|
|
function wrapNullable(nullable, typeAnnotation) {
|
|
if (!nullable) {
|
|
return typeAnnotation;
|
|
}
|
|
return {
|
|
type: 'NullableTypeAnnotation',
|
|
typeAnnotation,
|
|
};
|
|
}
|
|
function assertGenericTypeAnnotationHasExactlyOneTypeParameter(
|
|
moduleName,
|
|
/**
|
|
* TODO(T108222691): Use flow-types for @babel/parser
|
|
*/
|
|
typeAnnotation,
|
|
parser,
|
|
) {
|
|
if (typeAnnotation.typeParameters == null) {
|
|
throw new MissingTypeParameterGenericParserError(
|
|
moduleName,
|
|
typeAnnotation,
|
|
parser,
|
|
);
|
|
}
|
|
const typeAnnotationType = parser.typeParameterInstantiation;
|
|
invariant(
|
|
typeAnnotation.typeParameters.type === typeAnnotationType,
|
|
`assertGenericTypeAnnotationHasExactlyOneTypeParameter: Type parameters must be an AST node of type '${typeAnnotationType}'`,
|
|
);
|
|
if (typeAnnotation.typeParameters.params.length !== 1) {
|
|
throw new MoreThanOneTypeParameterGenericParserError(
|
|
moduleName,
|
|
typeAnnotation,
|
|
parser,
|
|
);
|
|
}
|
|
}
|
|
function isObjectProperty(property, language) {
|
|
switch (language) {
|
|
case 'Flow':
|
|
return property.type === 'ObjectTypeProperty';
|
|
case 'TypeScript':
|
|
return property.type === 'TSPropertySignature';
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
function getObjectTypeAnnotations(
|
|
hasteModuleName,
|
|
types,
|
|
tryParse,
|
|
translateTypeAnnotation,
|
|
parser,
|
|
) {
|
|
const aliasMap = {};
|
|
Object.entries(types).forEach(([key, value]) => {
|
|
const isTypeAlias =
|
|
value.type === 'TypeAlias' || value.type === 'TSTypeAliasDeclaration';
|
|
if (!isTypeAlias) {
|
|
return;
|
|
}
|
|
const parent = parser.nextNodeForTypeAlias(value);
|
|
if (
|
|
parent.type !== 'ObjectTypeAnnotation' &&
|
|
parent.type !== 'TSTypeLiteral'
|
|
) {
|
|
return;
|
|
}
|
|
const typeProperties = parser
|
|
.getAnnotatedElementProperties(value)
|
|
.map(prop =>
|
|
parseObjectProperty(
|
|
parent,
|
|
prop,
|
|
hasteModuleName,
|
|
types,
|
|
aliasMap,
|
|
{},
|
|
// enumMap
|
|
tryParse,
|
|
true,
|
|
// cxxOnly
|
|
(prop === null || prop === void 0 ? void 0 : prop.optional) || false,
|
|
translateTypeAnnotation,
|
|
parser,
|
|
),
|
|
);
|
|
aliasMap[key] = {
|
|
type: 'ObjectTypeAnnotation',
|
|
properties: typeProperties,
|
|
};
|
|
});
|
|
return aliasMap;
|
|
}
|
|
function parseObjectProperty(
|
|
parentObject,
|
|
property,
|
|
hasteModuleName,
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
nullable,
|
|
translateTypeAnnotation,
|
|
parser,
|
|
) {
|
|
const language = parser.language();
|
|
const name = parser.getKeyName(property, hasteModuleName);
|
|
const _property$optional = property.optional,
|
|
optional = _property$optional === void 0 ? false : _property$optional;
|
|
const languageTypeAnnotation =
|
|
language === 'TypeScript'
|
|
? property.typeAnnotation.typeAnnotation
|
|
: property.value;
|
|
|
|
// Handle recursive types
|
|
if (parentObject) {
|
|
var _languageTypeAnnotati, _languageTypeAnnotati2;
|
|
const propertyType = parser.getResolveTypeAnnotationFN()(
|
|
languageTypeAnnotation,
|
|
types,
|
|
parser,
|
|
);
|
|
if (
|
|
propertyType.typeResolutionStatus.successful === true &&
|
|
propertyType.typeResolutionStatus.type === 'alias' &&
|
|
(language === 'TypeScript'
|
|
? parentObject.typeName &&
|
|
parentObject.typeName.name ===
|
|
((_languageTypeAnnotati = languageTypeAnnotation.typeName) ===
|
|
null || _languageTypeAnnotati === void 0
|
|
? void 0
|
|
: _languageTypeAnnotati.name)
|
|
: parentObject.id &&
|
|
parentObject.id.name ===
|
|
((_languageTypeAnnotati2 = languageTypeAnnotation.id) === null ||
|
|
_languageTypeAnnotati2 === void 0
|
|
? void 0
|
|
: _languageTypeAnnotati2.name))
|
|
) {
|
|
if (!optional) {
|
|
throw new UnsupportedObjectDirectRecursivePropertyParserError(
|
|
name,
|
|
languageTypeAnnotation,
|
|
hasteModuleName,
|
|
);
|
|
}
|
|
return {
|
|
name,
|
|
optional,
|
|
typeAnnotation: {
|
|
type: 'TypeAliasTypeAnnotation',
|
|
name: propertyType.typeResolutionStatus.name,
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
// Handle non-recursive types
|
|
const _unwrapNullable = unwrapNullable(
|
|
translateTypeAnnotation(
|
|
hasteModuleName,
|
|
languageTypeAnnotation,
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
parser,
|
|
),
|
|
),
|
|
_unwrapNullable2 = _slicedToArray(_unwrapNullable, 2),
|
|
propertyTypeAnnotation = _unwrapNullable2[0],
|
|
isPropertyNullable = _unwrapNullable2[1];
|
|
if (
|
|
(propertyTypeAnnotation.type === 'FunctionTypeAnnotation' && !cxxOnly) ||
|
|
propertyTypeAnnotation.type === 'PromiseTypeAnnotation' ||
|
|
propertyTypeAnnotation.type === 'VoidTypeAnnotation'
|
|
) {
|
|
throwIfPropertyValueTypeIsUnsupported(
|
|
hasteModuleName,
|
|
languageTypeAnnotation,
|
|
property.key,
|
|
propertyTypeAnnotation.type,
|
|
);
|
|
}
|
|
return {
|
|
name,
|
|
optional,
|
|
typeAnnotation: wrapNullable(isPropertyNullable, propertyTypeAnnotation),
|
|
};
|
|
}
|
|
function translateFunctionTypeAnnotation(
|
|
hasteModuleName,
|
|
// TODO(T108222691): Use flow-types for @babel/parser
|
|
// TODO(T71778680): This is a FunctionTypeAnnotation. Type this.
|
|
functionTypeAnnotation,
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
translateTypeAnnotation,
|
|
parser,
|
|
) {
|
|
const params = [];
|
|
for (const param of parser.getFunctionTypeAnnotationParameters(
|
|
functionTypeAnnotation,
|
|
)) {
|
|
const parsedParam = tryParse(() => {
|
|
if (parser.getFunctionNameFromParameter(param) == null) {
|
|
throw new UnnamedFunctionParamParserError(param, hasteModuleName);
|
|
}
|
|
const paramName = parser.getParameterName(param);
|
|
const _unwrapNullable3 = unwrapNullable(
|
|
translateTypeAnnotation(
|
|
hasteModuleName,
|
|
parser.getParameterTypeAnnotation(param),
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
parser,
|
|
),
|
|
),
|
|
_unwrapNullable4 = _slicedToArray(_unwrapNullable3, 2),
|
|
paramTypeAnnotation = _unwrapNullable4[0],
|
|
isParamTypeAnnotationNullable = _unwrapNullable4[1];
|
|
if (
|
|
paramTypeAnnotation.type === 'VoidTypeAnnotation' ||
|
|
paramTypeAnnotation.type === 'PromiseTypeAnnotation'
|
|
) {
|
|
return throwIfUnsupportedFunctionParamTypeAnnotationParserError(
|
|
hasteModuleName,
|
|
param.typeAnnotation,
|
|
paramName,
|
|
paramTypeAnnotation.type,
|
|
);
|
|
}
|
|
return {
|
|
name: paramName,
|
|
optional: Boolean(param.optional),
|
|
typeAnnotation: wrapNullable(
|
|
isParamTypeAnnotationNullable,
|
|
paramTypeAnnotation,
|
|
),
|
|
};
|
|
});
|
|
if (parsedParam != null) {
|
|
params.push(parsedParam);
|
|
}
|
|
}
|
|
const _unwrapNullable5 = unwrapNullable(
|
|
translateTypeAnnotation(
|
|
hasteModuleName,
|
|
parser.getFunctionTypeAnnotationReturnType(functionTypeAnnotation),
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
parser,
|
|
),
|
|
),
|
|
_unwrapNullable6 = _slicedToArray(_unwrapNullable5, 2),
|
|
returnTypeAnnotation = _unwrapNullable6[0],
|
|
isReturnTypeAnnotationNullable = _unwrapNullable6[1];
|
|
throwIfUnsupportedFunctionReturnTypeAnnotationParserError(
|
|
hasteModuleName,
|
|
functionTypeAnnotation,
|
|
'FunctionTypeAnnotation',
|
|
cxxOnly,
|
|
returnTypeAnnotation.type,
|
|
);
|
|
return {
|
|
type: 'FunctionTypeAnnotation',
|
|
returnTypeAnnotation: wrapNullable(
|
|
isReturnTypeAnnotationNullable,
|
|
returnTypeAnnotation,
|
|
),
|
|
params,
|
|
};
|
|
}
|
|
function buildPropertySchema(
|
|
hasteModuleName,
|
|
// TODO(T108222691): [TS] Use flow-types for @babel/parser
|
|
// TODO(T71778680): [Flow] This is an ObjectTypeProperty containing either:
|
|
// - a FunctionTypeAnnotation or GenericTypeAnnotation
|
|
// - a NullableTypeAnnoation containing a FunctionTypeAnnotation or GenericTypeAnnotation
|
|
// Flow type this node
|
|
property,
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
translateTypeAnnotation,
|
|
parser,
|
|
) {
|
|
let nullable = false;
|
|
let key = property.key,
|
|
value = property.value;
|
|
const methodName = key.name;
|
|
if (parser.language() === 'TypeScript') {
|
|
value =
|
|
property.type === 'TSMethodSignature'
|
|
? property
|
|
: property.typeAnnotation;
|
|
}
|
|
const resolveTypeAnnotationFN = parser.getResolveTypeAnnotationFN();
|
|
var _resolveTypeAnnotatio = resolveTypeAnnotationFN(value, types, parser);
|
|
nullable = _resolveTypeAnnotatio.nullable;
|
|
value = _resolveTypeAnnotatio.typeAnnotation;
|
|
throwIfModuleTypeIsUnsupported(
|
|
hasteModuleName,
|
|
property.value,
|
|
key.name,
|
|
value.type,
|
|
parser,
|
|
);
|
|
return {
|
|
name: methodName,
|
|
optional: Boolean(property.optional),
|
|
typeAnnotation: wrapNullable(
|
|
nullable,
|
|
translateFunctionTypeAnnotation(
|
|
hasteModuleName,
|
|
value,
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
translateTypeAnnotation,
|
|
parser,
|
|
),
|
|
),
|
|
};
|
|
}
|
|
function buildEventEmitterSchema(
|
|
hasteModuleName,
|
|
// TODO(T108222691): [TS] Use flow-types for @babel/parser
|
|
// TODO(T71778680): [Flow] This is an ObjectTypeProperty containing either:
|
|
// - a FunctionTypeAnnotation or GenericTypeAnnotation
|
|
// - a NullableTypeAnnoation containing a FunctionTypeAnnotation or GenericTypeAnnotation
|
|
// Flow type this node
|
|
property,
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
translateTypeAnnotation,
|
|
parser,
|
|
) {
|
|
const key = property.key;
|
|
const value =
|
|
parser.language() === 'TypeScript'
|
|
? property.typeAnnotation.typeAnnotation
|
|
: property.value;
|
|
const eventemitterName = key.name;
|
|
const resolveTypeAnnotationFN = parser.getResolveTypeAnnotationFN();
|
|
const _unwrapNullable7 = unwrapNullable(value),
|
|
_unwrapNullable8 = _slicedToArray(_unwrapNullable7, 2),
|
|
typeAnnotation = _unwrapNullable8[0],
|
|
typeAnnotationNullable = _unwrapNullable8[1];
|
|
const typeAnnotationUntyped =
|
|
value.typeParameters.params.length === 1 &&
|
|
parser.language() === 'TypeScript'
|
|
? value.typeParameters.params[0].type === 'TSTypeLiteral' &&
|
|
value.typeParameters.params[0].members.length === 0
|
|
: value.typeParameters.params[0].type === 'ObjectTypeAnnotation' &&
|
|
value.typeParameters.params[0].properties.length === 0;
|
|
throwIfEventEmitterTypeIsUnsupported(
|
|
hasteModuleName,
|
|
key.name,
|
|
typeAnnotation.type,
|
|
parser,
|
|
typeAnnotationNullable,
|
|
typeAnnotationUntyped,
|
|
);
|
|
const eventTypeResolutionStatus = resolveTypeAnnotationFN(
|
|
typeAnnotation.typeParameters.params[0],
|
|
types,
|
|
parser,
|
|
);
|
|
throwIfEventEmitterEventTypeIsUnsupported(
|
|
hasteModuleName,
|
|
key.name,
|
|
eventTypeResolutionStatus.typeAnnotation,
|
|
parser,
|
|
eventTypeResolutionStatus.nullable,
|
|
);
|
|
const eventTypeAnnotation = translateTypeAnnotation(
|
|
hasteModuleName,
|
|
typeAnnotation.typeParameters.params[0],
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
parser,
|
|
);
|
|
return {
|
|
name: eventemitterName,
|
|
optional: false,
|
|
typeAnnotation: {
|
|
type: 'EventEmitterTypeAnnotation',
|
|
typeAnnotation: eventTypeAnnotation,
|
|
},
|
|
};
|
|
}
|
|
function buildSchemaFromConfigType(
|
|
configType,
|
|
filename,
|
|
ast,
|
|
wrapComponentSchema,
|
|
buildComponentSchema,
|
|
buildModuleSchema,
|
|
parser,
|
|
translateTypeAnnotation,
|
|
) {
|
|
switch (configType) {
|
|
case 'component': {
|
|
return wrapComponentSchema(buildComponentSchema(ast, parser));
|
|
}
|
|
case 'module': {
|
|
if (filename === undefined || filename === null) {
|
|
throw new Error('Filepath expected while parasing a module');
|
|
}
|
|
const nativeModuleName = extractNativeModuleName(filename);
|
|
const _createParserErrorCap = createParserErrorCapturer(),
|
|
_createParserErrorCap2 = _slicedToArray(_createParserErrorCap, 2),
|
|
parsingErrors = _createParserErrorCap2[0],
|
|
tryParse = _createParserErrorCap2[1];
|
|
const schema = tryParse(() =>
|
|
buildModuleSchema(
|
|
nativeModuleName,
|
|
ast,
|
|
tryParse,
|
|
parser,
|
|
translateTypeAnnotation,
|
|
),
|
|
);
|
|
if (parsingErrors.length > 0) {
|
|
/**
|
|
* TODO(T77968131): We have two options:
|
|
* - Throw the first error, but indicate there are more then one errors.
|
|
* - Display all errors, nicely formatted.
|
|
*
|
|
* For the time being, we're just throw the first error.
|
|
**/
|
|
|
|
throw parsingErrors[0];
|
|
}
|
|
invariant(
|
|
schema != null,
|
|
'When there are no parsing errors, the schema should not be null',
|
|
);
|
|
return wrapModuleSchema(schema, nativeModuleName);
|
|
}
|
|
default:
|
|
return {
|
|
modules: {},
|
|
};
|
|
}
|
|
}
|
|
function buildSchema(
|
|
contents,
|
|
filename,
|
|
wrapComponentSchema,
|
|
buildComponentSchema,
|
|
buildModuleSchema,
|
|
Visitor,
|
|
parser,
|
|
translateTypeAnnotation,
|
|
) {
|
|
// Early return for non-Spec JavaScript files
|
|
if (
|
|
!contents.includes('codegenNativeComponent') &&
|
|
!contents.includes('TurboModule')
|
|
) {
|
|
return {
|
|
modules: {},
|
|
};
|
|
}
|
|
const ast = parser.getAst(contents, filename);
|
|
const configType = getConfigType(ast, Visitor);
|
|
return buildSchemaFromConfigType(
|
|
configType,
|
|
filename,
|
|
ast,
|
|
wrapComponentSchema,
|
|
buildComponentSchema,
|
|
buildModuleSchema,
|
|
parser,
|
|
translateTypeAnnotation,
|
|
);
|
|
}
|
|
function createComponentConfig(foundConfig, commandsTypeNames) {
|
|
return _objectSpread(
|
|
_objectSpread({}, foundConfig),
|
|
{},
|
|
{
|
|
commandTypeName:
|
|
commandsTypeNames[0] == null
|
|
? null
|
|
: commandsTypeNames[0].commandTypeName,
|
|
commandOptionsExpression:
|
|
commandsTypeNames[0] == null
|
|
? null
|
|
: commandsTypeNames[0].commandOptionsExpression,
|
|
},
|
|
);
|
|
}
|
|
const parseModuleName = (hasteModuleName, moduleSpec, ast, parser) => {
|
|
const callExpressions = [];
|
|
visit(ast, {
|
|
CallExpression(node) {
|
|
if (isModuleRegistryCall(node)) {
|
|
callExpressions.push(node);
|
|
}
|
|
},
|
|
});
|
|
throwIfUnusedModuleInterfaceParserError(
|
|
hasteModuleName,
|
|
moduleSpec,
|
|
callExpressions,
|
|
);
|
|
throwIfMoreThanOneModuleRegistryCalls(
|
|
hasteModuleName,
|
|
callExpressions,
|
|
callExpressions.length,
|
|
);
|
|
const callExpression = callExpressions[0];
|
|
const typeParameters = parser.callExpressionTypeParameters(callExpression);
|
|
const methodName = callExpression.callee.property.name;
|
|
throwIfWrongNumberOfCallExpressionArgs(
|
|
hasteModuleName,
|
|
callExpression,
|
|
methodName,
|
|
callExpression.arguments.length,
|
|
);
|
|
throwIfIncorrectModuleRegistryCallArgument(
|
|
hasteModuleName,
|
|
callExpression.arguments[0],
|
|
methodName,
|
|
);
|
|
const $moduleName = callExpression.arguments[0].value;
|
|
throwIfUntypedModule(
|
|
typeParameters,
|
|
hasteModuleName,
|
|
callExpression,
|
|
methodName,
|
|
$moduleName,
|
|
);
|
|
throwIfIncorrectModuleRegistryCallTypeParameterParserError(
|
|
hasteModuleName,
|
|
typeParameters,
|
|
methodName,
|
|
$moduleName,
|
|
parser,
|
|
);
|
|
return $moduleName;
|
|
};
|
|
const buildModuleSchema = (
|
|
hasteModuleName,
|
|
ast,
|
|
tryParse,
|
|
parser,
|
|
translateTypeAnnotation,
|
|
) => {
|
|
const language = parser.language();
|
|
const types = parser.getTypes(ast);
|
|
const moduleSpecs = Object.values(types).filter(t =>
|
|
parser.isModuleInterface(t),
|
|
);
|
|
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 Name
|
|
const moduleName = parseModuleName(hasteModuleName, moduleSpec, ast, parser);
|
|
|
|
// 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, moduleName),
|
|
cxxOnly = _verifyPlatforms.cxxOnly,
|
|
excludedPlatforms = _verifyPlatforms.excludedPlatforms;
|
|
const aliasMap = cxxOnly
|
|
? getObjectTypeAnnotations(
|
|
hasteModuleName,
|
|
types,
|
|
tryParse,
|
|
translateTypeAnnotation,
|
|
parser,
|
|
)
|
|
: {};
|
|
const properties =
|
|
language === 'Flow' ? moduleSpec.body.properties : moduleSpec.body.body;
|
|
// $FlowFixMe[missing-type-arg]
|
|
const nativeModuleSchema = properties
|
|
.filter(
|
|
property =>
|
|
property.type === 'ObjectTypeProperty' ||
|
|
property.type === 'TSPropertySignature' ||
|
|
property.type === 'TSMethodSignature',
|
|
)
|
|
.map(property => {
|
|
var _property$typeAnnotat, _property$value, _property$value2;
|
|
const enumMap = {};
|
|
const isEventEmitter =
|
|
language === 'TypeScript'
|
|
? (property === null || property === void 0
|
|
? void 0
|
|
: property.type) === 'TSPropertySignature' &&
|
|
(property === null ||
|
|
property === void 0 ||
|
|
(_property$typeAnnotat = property.typeAnnotation) === null ||
|
|
_property$typeAnnotat === void 0 ||
|
|
(_property$typeAnnotat = _property$typeAnnotat.typeAnnotation) ===
|
|
null ||
|
|
_property$typeAnnotat === void 0 ||
|
|
(_property$typeAnnotat = _property$typeAnnotat.typeName) === null ||
|
|
_property$typeAnnotat === void 0
|
|
? void 0
|
|
: _property$typeAnnotat.name) === 'EventEmitter'
|
|
: (property === null ||
|
|
property === void 0 ||
|
|
(_property$value = property.value) === null ||
|
|
_property$value === void 0
|
|
? void 0
|
|
: _property$value.type) === 'GenericTypeAnnotation' &&
|
|
(property === null ||
|
|
property === void 0 ||
|
|
(_property$value2 = property.value) === null ||
|
|
_property$value2 === void 0 ||
|
|
(_property$value2 = _property$value2.id) === null ||
|
|
_property$value2 === void 0
|
|
? void 0
|
|
: _property$value2.name) === 'EventEmitter';
|
|
return tryParse(() => ({
|
|
aliasMap,
|
|
enumMap,
|
|
propertyShape: isEventEmitter
|
|
? {
|
|
type: 'eventEmitter',
|
|
value: buildEventEmitterSchema(
|
|
hasteModuleName,
|
|
property,
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
translateTypeAnnotation,
|
|
parser,
|
|
),
|
|
}
|
|
: {
|
|
type: 'method',
|
|
value: buildPropertySchema(
|
|
hasteModuleName,
|
|
property,
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
translateTypeAnnotation,
|
|
parser,
|
|
),
|
|
},
|
|
}));
|
|
})
|
|
.filter(Boolean)
|
|
.reduce(
|
|
(moduleSchema, {enumMap, propertyShape}) => ({
|
|
type: 'NativeModule',
|
|
aliasMap: _objectSpread(
|
|
_objectSpread({}, moduleSchema.aliasMap),
|
|
aliasMap,
|
|
),
|
|
enumMap: _objectSpread(
|
|
_objectSpread({}, moduleSchema.enumMap),
|
|
enumMap,
|
|
),
|
|
spec: {
|
|
eventEmitters: [...moduleSchema.spec.eventEmitters].concat(
|
|
propertyShape.type === 'eventEmitter' ? [propertyShape.value] : [],
|
|
),
|
|
methods: [...moduleSchema.spec.methods].concat(
|
|
propertyShape.type === 'method' ? [propertyShape.value] : [],
|
|
),
|
|
},
|
|
moduleName: moduleSchema.moduleName,
|
|
excludedPlatforms: moduleSchema.excludedPlatforms,
|
|
}),
|
|
{
|
|
type: 'NativeModule',
|
|
aliasMap: {},
|
|
enumMap: {},
|
|
spec: {
|
|
eventEmitters: [],
|
|
methods: [],
|
|
},
|
|
moduleName,
|
|
excludedPlatforms:
|
|
excludedPlatforms.length !== 0 ? [...excludedPlatforms] : undefined,
|
|
},
|
|
);
|
|
return {
|
|
type: 'NativeModule',
|
|
aliasMap: getSortedObject(nativeModuleSchema.aliasMap),
|
|
enumMap: getSortedObject(nativeModuleSchema.enumMap),
|
|
spec: {
|
|
eventEmitters: nativeModuleSchema.spec.eventEmitters.sort(),
|
|
methods: nativeModuleSchema.spec.methods.sort(),
|
|
},
|
|
moduleName,
|
|
excludedPlatforms: nativeModuleSchema.excludedPlatforms,
|
|
};
|
|
};
|
|
|
|
/**
|
|
* This function is used to find the type of a native component
|
|
* provided the default exports statement from generated AST.
|
|
* @param statement The statement to be parsed.
|
|
* @param foundConfigs The 'mutable' array of configs that have been found.
|
|
* @param parser The language parser to be used.
|
|
* @returns void
|
|
*/
|
|
function findNativeComponentType(statement, foundConfigs, parser) {
|
|
let declaration = statement.declaration;
|
|
|
|
// codegenNativeComponent can be nested inside a cast
|
|
// expression so we need to go one level deeper
|
|
if (
|
|
declaration.type === 'TSAsExpression' ||
|
|
declaration.type === 'AsExpression' ||
|
|
declaration.type === 'TypeCastExpression'
|
|
) {
|
|
declaration = declaration.expression;
|
|
}
|
|
try {
|
|
if (declaration.callee.name === 'codegenNativeComponent') {
|
|
const typeArgumentParams =
|
|
parser.getTypeArgumentParamsFromDeclaration(declaration);
|
|
const funcArgumentParams = declaration.arguments;
|
|
const nativeComponentType = parser.getNativeComponentType(
|
|
typeArgumentParams,
|
|
funcArgumentParams,
|
|
);
|
|
if (funcArgumentParams.length > 1) {
|
|
nativeComponentType.optionsExpression = funcArgumentParams[1];
|
|
}
|
|
foundConfigs.push(nativeComponentType);
|
|
}
|
|
} catch (e) {
|
|
// ignore
|
|
}
|
|
}
|
|
function getCommandOptions(commandOptionsExpression) {
|
|
if (commandOptionsExpression == null) {
|
|
return null;
|
|
}
|
|
let foundOptions;
|
|
try {
|
|
foundOptions = commandOptionsExpression.properties.reduce(
|
|
(options, prop) => {
|
|
options[prop.key.name] = (
|
|
(prop && prop.value && prop.value.elements) ||
|
|
[]
|
|
).map(element => element && element.value);
|
|
return options;
|
|
},
|
|
{},
|
|
);
|
|
} catch (e) {
|
|
throw new Error(
|
|
'Failed to parse command options, please check that they are defined correctly',
|
|
);
|
|
}
|
|
return foundOptions;
|
|
}
|
|
function getOptions(optionsExpression) {
|
|
if (!optionsExpression) {
|
|
return null;
|
|
}
|
|
let foundOptions;
|
|
try {
|
|
foundOptions = optionsExpression.properties.reduce((options, prop) => {
|
|
if (prop.value.type === 'ArrayExpression') {
|
|
options[prop.key.name] = prop.value.elements.map(
|
|
element => element.value,
|
|
);
|
|
} else {
|
|
options[prop.key.name] = prop.value.value;
|
|
}
|
|
return options;
|
|
}, {});
|
|
} catch (e) {
|
|
throw new Error(
|
|
'Failed to parse codegen options, please check that they are defined correctly',
|
|
);
|
|
}
|
|
if (
|
|
foundOptions.paperComponentName &&
|
|
foundOptions.paperComponentNameDeprecated
|
|
) {
|
|
throw new Error(
|
|
'Failed to parse codegen options, cannot use both paperComponentName and paperComponentNameDeprecated',
|
|
);
|
|
}
|
|
return foundOptions;
|
|
}
|
|
function getCommandTypeNameAndOptionsExpression(namedExport, parser) {
|
|
let callExpression;
|
|
let calleeName;
|
|
try {
|
|
callExpression = namedExport.declaration.declarations[0].init;
|
|
calleeName = callExpression.callee.name;
|
|
} catch (e) {
|
|
return;
|
|
}
|
|
if (calleeName !== 'codegenNativeCommands') {
|
|
return;
|
|
}
|
|
if (callExpression.arguments.length !== 1) {
|
|
throw new Error(
|
|
'codegenNativeCommands must be passed options including the supported commands',
|
|
);
|
|
}
|
|
const typeArgumentParam =
|
|
parser.getTypeArgumentParamsFromDeclaration(callExpression)[0];
|
|
if (!parser.isGenericTypeAnnotation(typeArgumentParam.type)) {
|
|
throw new Error(
|
|
"codegenNativeCommands doesn't support inline definitions. Specify a file local type alias",
|
|
);
|
|
}
|
|
return {
|
|
commandTypeName: parser.getTypeAnnotationName(typeArgumentParam),
|
|
commandOptionsExpression: callExpression.arguments[0],
|
|
};
|
|
}
|
|
function propertyNames(properties) {
|
|
return properties
|
|
.map(property => property && property.key && property.key.name)
|
|
.filter(Boolean);
|
|
}
|
|
function extendsForProp(prop, types, parser) {
|
|
const argument = parser.argumentForProp(prop);
|
|
if (!argument) {
|
|
console.log('null', prop);
|
|
}
|
|
const name = parser.nameForArgument(prop);
|
|
if (types[name] != null) {
|
|
// This type is locally defined in the file
|
|
return null;
|
|
}
|
|
switch (name) {
|
|
case 'ViewProps':
|
|
return {
|
|
type: 'ReactNativeBuiltInType',
|
|
knownTypeName: 'ReactNativeCoreViewProps',
|
|
};
|
|
default: {
|
|
throw new Error(`Unable to handle prop spread: ${name}`);
|
|
}
|
|
}
|
|
}
|
|
function buildPropSchema(property, types, parser) {
|
|
const getSchemaInfoFN = parser.getGetSchemaInfoFN();
|
|
const info = getSchemaInfoFN(property, types);
|
|
if (info == null) {
|
|
return null;
|
|
}
|
|
const name = info.name,
|
|
optional = info.optional,
|
|
typeAnnotation = info.typeAnnotation,
|
|
defaultValue = info.defaultValue,
|
|
withNullDefault = info.withNullDefault;
|
|
const getTypeAnnotationFN = parser.getGetTypeAnnotationFN();
|
|
return {
|
|
name,
|
|
optional,
|
|
typeAnnotation: getTypeAnnotationFN(
|
|
name,
|
|
typeAnnotation,
|
|
defaultValue,
|
|
withNullDefault,
|
|
types,
|
|
parser,
|
|
buildPropSchema,
|
|
),
|
|
};
|
|
}
|
|
|
|
/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
|
|
* LTI update could not be added via codemod */
|
|
function getEventArgument(argumentProps, parser, getPropertyType) {
|
|
return {
|
|
type: 'ObjectTypeAnnotation',
|
|
properties: argumentProps.map(member =>
|
|
buildPropertiesForEvent(member, parser, getPropertyType),
|
|
),
|
|
};
|
|
}
|
|
|
|
/* $FlowFixMe[signature-verification-failure] there's no flowtype for AST.
|
|
* TODO(T108222691): Use flow-types for @babel/parser */
|
|
function findComponentConfig(ast, parser) {
|
|
const foundConfigs = [];
|
|
const defaultExports = ast.body.filter(
|
|
node => node.type === 'ExportDefaultDeclaration',
|
|
);
|
|
defaultExports.forEach(statement => {
|
|
findNativeComponentType(statement, foundConfigs, parser);
|
|
});
|
|
throwIfConfigNotfound(foundConfigs);
|
|
throwIfMoreThanOneConfig(foundConfigs);
|
|
const foundConfig = foundConfigs[0];
|
|
const namedExports = ast.body.filter(
|
|
node => node.type === 'ExportNamedDeclaration',
|
|
);
|
|
const commandsTypeNames = namedExports
|
|
.map(statement => getCommandTypeNameAndOptionsExpression(statement, parser))
|
|
.filter(Boolean);
|
|
throwIfMoreThanOneCodegenNativecommands(commandsTypeNames);
|
|
return createComponentConfig(foundConfig, commandsTypeNames);
|
|
}
|
|
|
|
// $FlowFixMe[signature-verification-failure] there's no flowtype for AST
|
|
function getCommandProperties(ast, parser) {
|
|
const _findComponentConfig = findComponentConfig(ast, parser),
|
|
commandTypeName = _findComponentConfig.commandTypeName,
|
|
commandOptionsExpression = _findComponentConfig.commandOptionsExpression;
|
|
if (commandTypeName == null) {
|
|
return [];
|
|
}
|
|
const types = parser.getTypes(ast);
|
|
const typeAlias = types[commandTypeName];
|
|
throwIfTypeAliasIsNotInterface(typeAlias, parser);
|
|
const properties = parser.bodyProperties(typeAlias);
|
|
if (!properties) {
|
|
throw new Error(
|
|
`Failed to find type definition for "${commandTypeName}", please check that you have a valid codegen file`,
|
|
);
|
|
}
|
|
const commandPropertyNames = propertyNames(properties);
|
|
const commandOptions = getCommandOptions(commandOptionsExpression);
|
|
if (commandOptions == null || commandOptions.supportedCommands == null) {
|
|
throw new Error(
|
|
'codegenNativeCommands must be given an options object with supportedCommands array',
|
|
);
|
|
}
|
|
if (
|
|
commandOptions.supportedCommands.length !== commandPropertyNames.length ||
|
|
!commandOptions.supportedCommands.every(supportedCommand =>
|
|
commandPropertyNames.includes(supportedCommand),
|
|
)
|
|
) {
|
|
throw new Error(
|
|
`codegenNativeCommands expected the same supportedCommands specified in the ${commandTypeName} interface: ${commandPropertyNames.join(
|
|
', ',
|
|
)}`,
|
|
);
|
|
}
|
|
return properties;
|
|
}
|
|
function getTypeResolutionStatus(type, typeAnnotation, parser) {
|
|
return {
|
|
successful: true,
|
|
type,
|
|
name: parser.getTypeAnnotationName(typeAnnotation),
|
|
};
|
|
}
|
|
function handleGenericTypeAnnotation(
|
|
typeAnnotation,
|
|
resolvedTypeAnnotation,
|
|
parser,
|
|
) {
|
|
let typeResolutionStatus;
|
|
let node;
|
|
switch (resolvedTypeAnnotation.type) {
|
|
case parser.typeAlias: {
|
|
typeResolutionStatus = getTypeResolutionStatus(
|
|
'alias',
|
|
typeAnnotation,
|
|
parser,
|
|
);
|
|
node = parser.nextNodeForTypeAlias(resolvedTypeAnnotation);
|
|
break;
|
|
}
|
|
case parser.enumDeclaration: {
|
|
typeResolutionStatus = getTypeResolutionStatus(
|
|
'enum',
|
|
typeAnnotation,
|
|
parser,
|
|
);
|
|
node = parser.nextNodeForEnum(resolvedTypeAnnotation);
|
|
break;
|
|
}
|
|
// parser.interfaceDeclaration is not used here because for flow it should fall through to default case and throw an error
|
|
case 'TSInterfaceDeclaration': {
|
|
typeResolutionStatus = getTypeResolutionStatus(
|
|
'alias',
|
|
typeAnnotation,
|
|
parser,
|
|
);
|
|
node = resolvedTypeAnnotation;
|
|
break;
|
|
}
|
|
default: {
|
|
throw new TypeError(
|
|
parser.genericTypeAnnotationErrorMessage(resolvedTypeAnnotation),
|
|
);
|
|
}
|
|
}
|
|
return {
|
|
typeAnnotation: node,
|
|
typeResolutionStatus,
|
|
};
|
|
}
|
|
function buildPropertiesForEvent(property, parser, getPropertyType) {
|
|
const name = property.key.name;
|
|
const optional = parser.isOptionalProperty(property);
|
|
const typeAnnotation = parser.getTypeAnnotationFromProperty(property);
|
|
return getPropertyType(name, optional, typeAnnotation, parser);
|
|
}
|
|
function verifyPropNotAlreadyDefined(props, needleProp) {
|
|
const propName = needleProp.key.name;
|
|
const foundProp = props.some(prop => prop.key.name === propName);
|
|
if (foundProp) {
|
|
throw new Error(`A prop was already defined with the name ${propName}`);
|
|
}
|
|
}
|
|
function handleEventHandler(
|
|
name,
|
|
typeAnnotation,
|
|
parser,
|
|
types,
|
|
findEventArgumentsAndType,
|
|
) {
|
|
const eventType = name === 'BubblingEventHandler' ? 'bubble' : 'direct';
|
|
const paperTopLevelNameDeprecated =
|
|
parser.getPaperTopLevelNameDeprecated(typeAnnotation);
|
|
switch (typeAnnotation.typeParameters.params[0].type) {
|
|
case parser.nullLiteralTypeAnnotation:
|
|
case parser.undefinedLiteralTypeAnnotation:
|
|
return {
|
|
argumentProps: [],
|
|
bubblingType: eventType,
|
|
paperTopLevelNameDeprecated,
|
|
};
|
|
default:
|
|
return findEventArgumentsAndType(
|
|
parser,
|
|
typeAnnotation.typeParameters.params[0],
|
|
types,
|
|
eventType,
|
|
paperTopLevelNameDeprecated,
|
|
);
|
|
}
|
|
}
|
|
function emitBuildEventSchema(
|
|
paperTopLevelNameDeprecated,
|
|
name,
|
|
optional,
|
|
nonNullableBubblingType,
|
|
argument,
|
|
) {
|
|
if (paperTopLevelNameDeprecated != null) {
|
|
return {
|
|
name,
|
|
optional,
|
|
bubblingType: nonNullableBubblingType,
|
|
paperTopLevelNameDeprecated,
|
|
typeAnnotation: {
|
|
type: 'EventTypeAnnotation',
|
|
argument: argument,
|
|
},
|
|
};
|
|
}
|
|
return {
|
|
name,
|
|
optional,
|
|
bubblingType: nonNullableBubblingType,
|
|
typeAnnotation: {
|
|
type: 'EventTypeAnnotation',
|
|
argument: argument,
|
|
},
|
|
};
|
|
}
|
|
module.exports = {
|
|
wrapModuleSchema,
|
|
unwrapNullable,
|
|
wrapNullable,
|
|
assertGenericTypeAnnotationHasExactlyOneTypeParameter,
|
|
isObjectProperty,
|
|
parseObjectProperty,
|
|
translateFunctionTypeAnnotation,
|
|
buildPropertySchema,
|
|
buildSchemaFromConfigType,
|
|
buildSchema,
|
|
createComponentConfig,
|
|
parseModuleName,
|
|
buildModuleSchema,
|
|
findNativeComponentType,
|
|
propertyNames,
|
|
getCommandOptions,
|
|
getOptions,
|
|
getCommandTypeNameAndOptionsExpression,
|
|
extendsForProp,
|
|
buildPropSchema,
|
|
getEventArgument,
|
|
findComponentConfig,
|
|
getCommandProperties,
|
|
handleGenericTypeAnnotation,
|
|
getTypeResolutionStatus,
|
|
buildPropertiesForEvent,
|
|
verifyPropNotAlreadyDefined,
|
|
handleEventHandler,
|
|
emitBuildEventSchema,
|
|
};
|