UNPKG

react-native-codegen

Version:
203 lines (182 loc) 5.39 kB
/** * 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. * * @flow strict * @format */ 'use strict'; import type { Nullable, NativeModuleObjectTypeAnnotation, NativeModuleStringTypeAnnotation, NativeModuleNumberTypeAnnotation, NativeModuleInt32TypeAnnotation, NativeModuleDoubleTypeAnnotation, NativeModuleFloatTypeAnnotation, NativeModuleBooleanTypeAnnotation, NativeModuleGenericObjectTypeAnnotation, ReservedTypeAnnotation, NativeModuleTypeAliasTypeAnnotation, NativeModuleArrayTypeAnnotation, NativeModuleBaseTypeAnnotation, } from '../../../CodegenSchema'; import type {AliasResolver} from '../Utils'; const {capitalize} = require('../../Utils'); const { unwrapNullable, wrapNullable, } = require('../../../parsers/flow/modules/utils'); type StructContext = 'CONSTANTS' | 'REGULAR'; export type RegularStruct = $ReadOnly<{ context: 'REGULAR', name: string, properties: $ReadOnlyArray<StructProperty>, }>; export type ConstantsStruct = $ReadOnly<{ context: 'CONSTANTS', name: string, properties: $ReadOnlyArray<StructProperty>, }>; export type Struct = RegularStruct | ConstantsStruct; export type StructProperty = $ReadOnly<{ name: string, optional: boolean, typeAnnotation: Nullable<StructTypeAnnotation>, }>; export type StructTypeAnnotation = | NativeModuleStringTypeAnnotation | NativeModuleNumberTypeAnnotation | NativeModuleInt32TypeAnnotation | NativeModuleDoubleTypeAnnotation | NativeModuleFloatTypeAnnotation | NativeModuleBooleanTypeAnnotation | NativeModuleGenericObjectTypeAnnotation | ReservedTypeAnnotation | NativeModuleTypeAliasTypeAnnotation | NativeModuleArrayTypeAnnotation<Nullable<StructTypeAnnotation>>; class StructCollector { _structs: Map<string, Struct> = new Map(); process( structName: string, structContext: StructContext, resolveAlias: AliasResolver, nullableTypeAnnotation: Nullable<NativeModuleBaseTypeAnnotation>, ): Nullable<StructTypeAnnotation> { const [typeAnnotation, nullable] = unwrapNullable(nullableTypeAnnotation); switch (typeAnnotation.type) { case 'ObjectTypeAnnotation': { this._insertStruct( structName, structContext, resolveAlias, typeAnnotation, ); return wrapNullable(nullable, { type: 'TypeAliasTypeAnnotation', name: structName, }); } case 'ArrayTypeAnnotation': { if (typeAnnotation.elementType == null) { return wrapNullable(nullable, { type: 'ArrayTypeAnnotation', }); } return wrapNullable(nullable, { type: 'ArrayTypeAnnotation', elementType: this.process( structName + 'Element', structContext, resolveAlias, typeAnnotation.elementType, ), }); } case 'TypeAliasTypeAnnotation': { this._insertAlias(typeAnnotation.name, structContext, resolveAlias); return wrapNullable(nullable, typeAnnotation); } case 'MixedTypeAnnotation': throw new Error('Mixed types are unsupported in structs'); default: { return wrapNullable(nullable, typeAnnotation); } } } _insertAlias( aliasName: string, structContext: StructContext, resolveAlias: AliasResolver, ): void { const usedStruct = this._structs.get(aliasName); if (usedStruct == null) { this._insertStruct( aliasName, structContext, resolveAlias, resolveAlias(aliasName), ); } else if (usedStruct.context !== structContext) { throw new Error( `Tried to use alias '${aliasName}' in a getConstants() return type and inside a regular struct.`, ); } } _insertStruct( structName: string, structContext: StructContext, resolveAlias: AliasResolver, objectTypeAnnotation: NativeModuleObjectTypeAnnotation, ): void { // $FlowFixMe[missing-type-arg] const properties = objectTypeAnnotation.properties.map< $ReadOnly<{ name: string, optional: boolean, typeAnnotation: Nullable<StructTypeAnnotation>, }>, >(property => { const propertyStructName = structName + capitalize(property.name); return { ...property, typeAnnotation: this.process( propertyStructName, structContext, resolveAlias, property.typeAnnotation, ), }; }); switch (structContext) { case 'REGULAR': this._structs.set(structName, { name: structName, context: 'REGULAR', properties: properties, }); break; case 'CONSTANTS': this._structs.set(structName, { name: structName, context: 'CONSTANTS', properties: properties, }); break; default: (structContext: empty); throw new Error(`Detected an invalid struct context: ${structContext}`); } } getAllStructs(): $ReadOnlyArray<Struct> { return [...this._structs.values()]; } getStruct(name: string): ?Struct { return this._structs.get(name); } } module.exports = { StructCollector, };