Skip to content

Commit

Permalink
Codegen: JavaGenerator [3] - parse aliases and reserved value types
Browse files Browse the repository at this point in the history
Summary:
This parses the JSON schema's aliases and reserved function valye types. It also assigns TypeId correctly now:
* TypeId is an identifier for a specific type, that can be referred by others
* This means only aliases should have TypeId.typeName. Properties' names are not typeNames
* NativeModule spec's typeName is hardcoded to `Spec`, see T71955395

This way, whenever we encounter an `AliasType`, we can just lookup the actual Type by a quick Map lookup with TypeId as the key.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D23181432

fbshipit-source-id: 9d0ea17dbf601589d8f3fc1955e0c9406a80e244
  • Loading branch information
fkgozali authored and facebook-github-bot committed Aug 18, 2020
1 parent 4231551 commit eecb930
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ gradlePlugin {

dependencies {
implementation 'com.android.tools.build:gradle:3.5.3'
implementation 'com.google.code.gson:gson:2.8.6'
// Use the same Gson version that `com.android.tools.build:gradle` depends on.
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.google.guava:guava:29.0-jre'
implementation 'com.squareup:javapoet:1.13.0'
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

package com.facebook.react.codegen.generator;

import com.facebook.react.codegen.generator.model.RawSchema;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
Expand All @@ -28,6 +29,10 @@ public JavaGenerator(final File schemaFile, final String javaPackageName, final
}

public void build() throws FileNotFoundException, IOException {
final RawSchema rawSchema = SchemaJsonParser.parse(mSchemaFile);
// TODO (T71663018): remove - this is for debugging
System.out.println(rawSchema);

final MethodSpec main =
MethodSpec.methodBuilder("main")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

Expand All @@ -47,7 +46,7 @@ public static RawSchema parse(final File schemaFile) throws FileNotFoundExceptio
final JsonParser parser = new JsonParser();
final JsonElement rootElement = parser.parse(new FileReader(schemaFile));

final Map<String, List<NativeModuleType>> collection = new HashMap<>();
final Map<String, Map<String, NativeModuleType>> collection = new HashMap<>();

if (rootElement.isJsonObject()) {
final JsonObject root = rootElement.getAsJsonObject();
Expand All @@ -67,13 +66,16 @@ public static RawSchema parse(final File schemaFile) throws FileNotFoundExceptio
collection.put(
jsModuleName,
nativeModules.entrySet().stream()
.map(
nativeModuleEntry -> {
return parseNativeModule(
TypeId.of(jsModuleName, nativeModuleEntry.getKey()),
nativeModuleEntry.getValue().getAsJsonObject());
})
.collect(Collectors.toList()));
.collect(
Collectors.toMap(
Map.Entry::getKey,
e -> {
return parseNativeModule(
// TODO (T71955395): NativeModule spec type name does not
// exist in the schema. For now assume it's "Spec".
TypeId.of(jsModuleName, "Spec"),
e.getValue().getAsJsonObject());
})));
});
}

Expand All @@ -84,23 +86,35 @@ private static NativeModuleType parseNativeModule(final TypeId typeId, final Jso
final JsonObject aliases = json.getAsJsonObject("aliases");
final JsonArray properties = json.getAsJsonArray("properties");

// TODO: parse aliases
final ImmutableList<Type> collectedAliases =
ImmutableList.copyOf(
aliases.entrySet().stream()
.map(
entry -> {
final String typeName = entry.getKey();
final JsonObject typeAnnotation = entry.getValue().getAsJsonObject();
// The alias name is the type name that other types can refer to.
return parseTypeAnnotation(
TypeId.of(typeId.moduleName, typeName), typeAnnotation);
})
.collect(Collectors.toList()));

ImmutableList.Builder<NativeModuleType.Property> methods = new ImmutableList.Builder<>();
ImmutableList.Builder<NativeModuleType.Property> collectedPropertiesBuilder =
new ImmutableList.Builder<>();
properties.forEach(
p -> {
final JsonObject node = p.getAsJsonObject();
final String name = node.has("name") ? node.get("name").getAsString() : null;
final JsonObject typeAnnotation = node.getAsJsonObject("typeAnnotation");
// TODO (T71845349): "optional" field shouldn't be part of the Function's typeAnnotation.
final boolean optional = typeAnnotation.get("optional").getAsBoolean();
final TypeId propertyTypeId = TypeId.of(typeId.moduleName, name);
methods.add(
final TypeId propertyTypeId = TypeId.of(typeId.moduleName);
collectedPropertiesBuilder.add(
new NativeModuleType.Property(
name, parseTypeAnnotation(propertyTypeId, typeAnnotation), optional));
});

return new NativeModuleType(typeId, methods.build());
return new NativeModuleType(typeId, collectedAliases, collectedPropertiesBuilder.build());
}

// Parse type information from a JSON "typeAnnotation" node.
Expand All @@ -115,8 +129,7 @@ private static Type parseTypeAnnotation(final TypeId typeId, final JsonObject ty

switch (type) {
case AliasType.TYPE_NAME:
// TODO
parsedType = new AliasType(typeId, typeId);
parsedType = parseAliasTypeAnnotation(typeId, typeAnnotation);
break;
case AnyType.TYPE_NAME:
parsedType = new AnyType(typeId);
Expand Down Expand Up @@ -152,9 +165,8 @@ private static Type parseTypeAnnotation(final TypeId typeId, final JsonObject ty
parsedType = new PromiseType(typeId);
break;
case ReservedFunctionValueType.TYPE_NAME:
// TODO
parsedType =
new ReservedFunctionValueType(typeId, ReservedFunctionValueType.ReservedName.RootTag);
parsedType = parseReservedFunctionValueTypeAnnotation(typeId, typeAnnotation);
break;
case StringType.TYPE_NAME:
parsedType = new StringType(typeId);
break;
Expand All @@ -167,19 +179,20 @@ private static Type parseTypeAnnotation(final TypeId typeId, final JsonObject ty
return maybeCreateNullableType(nullable, parsedType);
}

private static Type parseAliasTypeAnnotation(
final TypeId typeId, final JsonObject typeAnnotation) {
// For now, assume the alias lives inside the same file.
return new AliasType(
typeId, TypeId.of(typeId.moduleName, typeAnnotation.get("name").getAsString()));
}

private static Type parseArrayTypeAnnotation(
final TypeId typeId, final JsonObject typeAnnotation) {
final JsonObject elementTypeAnnotation = typeAnnotation.getAsJsonObject("elementType");
// TODO (T71847026): Some array types are missing elementType annotation.
final Type elementType =
elementTypeAnnotation != null
? parseTypeAnnotation(
TypeId.of(
typeId.moduleName,
elementTypeAnnotation.has("name")
? elementTypeAnnotation.get("name").getAsString()
: null),
elementTypeAnnotation)
? parseTypeAnnotation(TypeId.of(typeId.moduleName), elementTypeAnnotation)
: new AnyType(TypeId.of(typeId.moduleName));

return new ArrayType(typeId, elementType);
Expand All @@ -201,8 +214,7 @@ private static Type parseFunctionTypeAnnotation(
FunctionType.createArgument(
name,
parseTypeAnnotation(
TypeId.of(typeId.moduleName, name),
node.getAsJsonObject("typeAnnotation"))));
TypeId.of(typeId.moduleName), node.getAsJsonObject("typeAnnotation"))));
});
}

Expand All @@ -227,7 +239,7 @@ private static Type parseObjectTypeAnnotation(
final String name = node.has("name") ? node.get("name").getAsString() : null;
final boolean optional = node.get("optional").getAsBoolean();
final JsonObject propertyTypeAnnotation = node.getAsJsonObject("typeAnnotation");
final TypeId propertyTypeId = TypeId.of(typeId.moduleName, name);
final TypeId propertyTypeId = TypeId.of(typeId.moduleName);

// TODO (T67898313): Some object properties are missing typeAnnotation.
final Type propertyType =
Expand All @@ -241,6 +253,13 @@ private static Type parseObjectTypeAnnotation(
return new ObjectType(typeId, propertiesList.build());
}

private static Type parseReservedFunctionValueTypeAnnotation(
final TypeId typeId, final JsonObject typeAnnotation) {
return new ReservedFunctionValueType(
typeId,
ReservedFunctionValueType.ReservedName.valueOf(typeAnnotation.get("name").getAsString()));
}

private static Type maybeCreateNullableType(final boolean nullable, final Type original) {
if (!nullable || original instanceof VoidType) {
return original;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
public final class NativeModuleType extends Type {
public static String TYPE_NAME = "<NONE>"; // Not an actual type in the schema.

public final List<Type> aliases;
public final List<Property> properties;

public static class Property {
Expand All @@ -33,13 +34,15 @@ public String toString() {
}
}

public NativeModuleType(final TypeId typeId, final List<Property> properties) {
public NativeModuleType(
final TypeId typeId, final List<Type> aliases, final List<Property> properties) {
super(typeId);
this.aliases = Collections.unmodifiableList(aliases);
this.properties = Collections.unmodifiableList(properties);
}

@Override
public String toString() {
return getTypeId() + " -> " + properties;
return getTypeId() + "\n aliases: " + aliases + "\n properties: " + properties;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@

package com.facebook.react.codegen.generator.model;

import java.util.List;
import java.util.Collections;
import java.util.Map;

/** Represents the parsed JSON schema without any type resolution. */
public final class RawSchema {

public final Map<String, List<NativeModuleType>> modules;
public final Map<String, Map<String, NativeModuleType>> modules;

public RawSchema(final Map<String, List<NativeModuleType>> modules) {
this.modules = modules;
public RawSchema(final Map<String, Map<String, NativeModuleType>> modules) {
this.modules = Collections.unmodifiableMap(modules);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static TypeId of(final TypeId typeId) {
public String toString() {
return String.format(
"<moduleName = %s, typeName = %s>",
moduleName, EMPTY_TYPE_NAME.equals(typeName) ? moduleName : typeName);
moduleName, EMPTY_TYPE_NAME.equals(typeName) ? "\"\"" : typeName);
}

@Override
Expand Down

0 comments on commit eecb930

Please sign in to comment.