@@ -326,6 +326,22 @@ private void createClassesAndEnums(JsonObject jsonObject) {
326326 }
327327 return ;
328328 }
329+ if ("function" .equals (jsonObject .get ("name" ).getAsString ()) && jsonObject .has ("args" )) {
330+ for (JsonElement item : jsonObject .getAsJsonArray ("args" )) {
331+ if (!item .isJsonObject ()) {
332+ continue ;
333+ }
334+ JsonObject argObject = item .getAsJsonObject ();
335+ if (!"Object" .equals (argObject .get ("name" ).getAsString ())) {
336+ continue ;
337+ }
338+ String alias = javaAlias (argObject );
339+ if (alias != null ) {
340+ typeScope ().createTopLevelInterface (alias , this , argObject );
341+ }
342+ }
343+ return ;
344+ }
329345 if ("Object" .equals (jsonObject .get ("name" ).getAsString ())) {
330346 if (customType != null ) {
331347 // Same type maybe referenced as 'Object' in several union values, e.g. Object|Array<Object>
@@ -506,8 +522,8 @@ private String convertBuiltinType(JsonObject jsonType) {
506522 if (customType != null ) {
507523 return customType ;
508524 }
509- // Inner Objects (e.g. function arguments) are not visited by createClassesAndEnums,
510- // so resolve their Java type name from langAliases here.
525+ // Inner Objects without langAliases (e.g. unaliased function arguments) are not visited
526+ // by createClassesAndEnums, so resolve their Java type name from langAliases here.
511527 String alias = javaAlias (jsonType );
512528 if (alias != null ) {
513529 return alias ;
@@ -601,6 +617,14 @@ void createTopLevelClass(String name, Element parent, JsonObject jsonObject) {
601617 }
602618 }
603619
620+ void createTopLevelInterface (String name , Element parent , JsonObject jsonObject ) {
621+ Map <String , TypeDefinition > map = topLevelTypes ();
622+ TypeDefinition existing = map .putIfAbsent (name , new CustomInterface (parent , name , jsonObject ));
623+ if (existing != null && !(existing instanceof CustomInterface )) {
624+ throw new RuntimeException ("Two interfaces with same name have different values:\n " + jsonObject + "\n " + existing .jsonElement );
625+ }
626+ }
627+
604628 void createNestedClass (String name , Element parent , JsonObject jsonObject ) {
605629 for (CustomClass c : classes ) {
606630 if (c .name .equals (name )) {
@@ -840,7 +864,7 @@ class Field extends Element {
840864 final String name ;
841865 final TypeRef type ;
842866
843- Field (CustomClass parent , String name , JsonObject jsonElement ) {
867+ Field (TypeDefinition parent , String name , JsonObject jsonElement ) {
844868 super (parent , jsonElement );
845869 this .name = name ;
846870 this .type = new TypeRef (this , jsonElement .getAsJsonObject ().get ("type" ));
@@ -1151,6 +1175,43 @@ private void writeConstructor(List<String> output, String bodyOffset) {
11511175 }
11521176}
11531177
1178+ class CustomInterface extends TypeDefinition {
1179+ final String name ;
1180+ final List <Field > fields = new ArrayList <>();
1181+
1182+ CustomInterface (Element parent , String name , JsonObject jsonElement ) {
1183+ super (parent , true , jsonElement );
1184+ this .name = name ;
1185+ if (jsonElement .has ("properties" )) {
1186+ for (JsonElement item : jsonElement .getAsJsonArray ("properties" )) {
1187+ JsonObject propertyJson = item .getAsJsonObject ();
1188+ fields .add (new Field (this , propertyJson .get ("name" ).getAsString (), propertyJson ));
1189+ }
1190+ }
1191+ }
1192+
1193+ @ Override
1194+ String name () {
1195+ return name ;
1196+ }
1197+
1198+ @ Override
1199+ void writeTo (List <String > output , String offset ) {
1200+ output .add (offset + "public interface " + name + " {" );
1201+ String bodyOffset = offset + " " ;
1202+ boolean first = true ;
1203+ for (Field f : fields ) {
1204+ if (!first ) {
1205+ output .add ("" );
1206+ }
1207+ first = false ;
1208+ writeJavadoc (output , bodyOffset , f .comment ());
1209+ output .add (bodyOffset + f .type .toJava () + " " + f .name + "();" );
1210+ }
1211+ output .add (offset + "}" );
1212+ }
1213+ }
1214+
11541215class Enum extends TypeDefinition {
11551216 final List <String > enumValues ;
11561217
@@ -1199,18 +1260,25 @@ public class ApiGenerator {
11991260 System .out .println ("Writing assertion files to: " + dir .getCanonicalPath ());
12001261 generate (api , assertionsDir , "com.microsoft.playwright.assertions" , isAssertion ().and (isSoftAssertion ().negate ()), sharedTypes );
12011262
1202- writeTopLevelTypes (sharedTypes , optionsDir , "com.microsoft.playwright" );
1263+ writeTopLevelTypes (sharedTypes , dir , optionsDir , "com.microsoft.playwright" );
12031264 }
12041265
1205- private void writeTopLevelTypes (Map <String , TypeDefinition > topLevelTypes , File optionsDir , String packageName ) throws IOException {
1266+ private void writeTopLevelTypes (Map <String , TypeDefinition > topLevelTypes , File dir , File optionsDir , String packageName ) throws IOException {
12061267 for (TypeDefinition e : topLevelTypes .values ()) {
12071268 List <String > lines = new ArrayList <>();
12081269 lines .add (Interface .header );
1209- lines .add ("package " + packageName + ".options;" );
1270+ File targetDir ;
1271+ if (e instanceof CustomInterface ) {
1272+ lines .add ("package " + packageName + ";" );
1273+ targetDir = dir ;
1274+ } else {
1275+ lines .add ("package " + packageName + ".options;" );
1276+ targetDir = optionsDir ;
1277+ }
12101278 lines .add ("" );
12111279 e .writeTo (lines , "" );
12121280 String text = String .join ("\n " , lines );
1213- try (FileWriter writer = new FileWriter (new File (optionsDir , e .name () + ".java" ))) {
1281+ try (FileWriter writer = new FileWriter (new File (targetDir , e .name () + ".java" ))) {
12141282 writer .write (text );
12151283 }
12161284 }
0 commit comments