···245 "unknown"
246 in
247 type_name (context ^ "_" ^ def_name)
248+249+(** group NSIDs by shared prefixes
250+ e.g. ["app.bsky.actor.defs"; "app.bsky.actor.getProfile"; "app.bsky.graph.defs"; "com.atproto.sync.getRepo"]
251+ -> [("app", Node [("bsky", Node [("actor", Node [("defs", Module "app.bsky.actor.defs"); ("getProfile", Module "app.bsky.actor.getProfile")]);
252+ ("graph", Node [("defs", Module "app.bsky.graph.defs")])])]);
253+ ("com", [("atproto", [("sync", [("getRepo", Module "com.atproto.sync.getRepo")])])])] *)
254+type trie = Node of (string * trie) list | Module of string
255+256+let group_nsids_by_prefix nsids =
257+ let rec insert_segments trie nsid segments =
258+ match segments with
259+ | [] ->
260+ Module nsid
261+ | seg :: rest ->
262+ let children =
263+ match trie with Node node_children -> node_children | Module _ -> []
264+ in
265+ let existing =
266+ match List.assoc_opt seg children with
267+ | Some child ->
268+ child
269+ | None ->
270+ Node []
271+ in
272+ let updated = insert_segments existing nsid rest in
273+ let trie_without_seg = List.remove_assoc seg children in
274+ Node ((seg, updated) :: trie_without_seg)
275+ in
276+ match
277+ List.fold_left
278+ (fun trie nsid ->
279+ let segments = String.split_on_char '.' nsid in
280+ insert_segments trie nsid segments )
281+ (Node []) nsids
282+ with
283+ | Node result ->
284+ result
285+ | _ ->
286+ failwith "unexpected trie type"
+1-1
hermes/README.md
···39 let client = Hermes.make_client ~service:"https://public.api.bsky.app" () in
4041 (* Make a query using the generated module *)
42- let* profile = App_bsky_actor_getProfile.call ~actor:"bsky.app" client in
43 print_endline profile.display_name;
44 Lwt.return_unit
45end
···39 let client = Hermes.make_client ~service:"https://public.api.bsky.app" () in
4041 (* Make a query using the generated module *)
42+ let* profile = App.Bsky.Actor.Profile.call ~actor:"bsky.app" client in
43 print_endline profile.display_name;
44 Lwt.return_unit
45end
+14-31
hermes_ppx/lib/hermes_ppx.ml
···4let nsid_to_module_path nsid =
5 String.split_on_char '.' nsid |> List.map String.capitalize_ascii
67-(* convert nsid to flat module name: "com.atproto.identity.resolveHandle" -> "Com_atproto_identity_resolveHandle" *)
8-let nsid_to_flat_module_name nsid =
9- let flat = String.concat "_" (String.split_on_char '.' nsid) in
10- String.capitalize_ascii flat
11-12-(* build module access expression from path: ["App"; "Bsky"] -> App.Bsky *)
13-let build_module_path ~loc path =
14- match path with
15- | [] ->
16- Location.raise_errorf ~loc "Empty module path"
17- | first :: rest ->
18- List.fold_left
19- (fun acc part ->
20- let lid = Loc.make ~loc (Longident.Ldot (acc.txt, part)) in
21- lid )
22- (Loc.make ~loc (Longident.Lident first))
23- rest
24-25-(* build full expression for flat module structure: Module_name.Main.call *)
26-let build_call_expr_flat ~loc nsid =
27- let module_name = nsid_to_flat_module_name nsid in
28- (* Build: Module_name.Main.call *)
29- let lid = Longident.(Ldot (Ldot (Lident module_name, "Main"), "call")) in
30 Ast_builder.Default.pexp_ident ~loc (Loc.make ~loc lid)
31-32-(* build full expression: Module.Path.call (nested style, kept for compatibility) *)
33-let build_call_expr ~loc nsid =
34- let parts = nsid_to_module_path nsid in
35- let module_lid = build_module_path ~loc parts in
36- let call_lid = Loc.make ~loc (Longident.Ldot (module_lid.txt, "call")) in
37- Ast_builder.Default.pexp_ident ~loc call_lid
3839(* parse method and nsid from structure items *)
40let parse_method_and_nsid ~loc str =
···65let expand ~ctxt str =
66 let loc = Expansion_context.Extension.extension_point_loc ctxt in
67 let _method, nsid = parse_method_and_nsid ~loc str in
68- build_call_expr_flat ~loc nsid
6970let xrpc_extension =
71 Extension.V3.declare "xrpc" Extension.Context.expression
···4let nsid_to_module_path nsid =
5 String.split_on_char '.' nsid |> List.map String.capitalize_ascii
67+(* build full expression: Module.Name.Main.call *)
8+let build_call_expr ~loc nsid =
9+ let module_path = nsid_to_module_path nsid in
10+ let module_lid =
11+ match module_path with
12+ | [] ->
13+ Location.raise_errorf ~loc "Expected non-empty nsid"
14+ | hd :: tl ->
15+ List.fold_left
16+ (fun acc part -> Longident.Ldot (acc, part))
17+ (Longident.Lident hd) tl
18+ in
19+ let lid = Longident.(Ldot (Ldot (module_lid, "Main"), "call")) in
000000000020 Ast_builder.Default.pexp_ident ~loc (Loc.make ~loc lid)
00000002122(* parse method and nsid from structure items *)
23let parse_method_and_nsid ~loc str =
···48let expand ~ctxt str =
49 let loc = Expansion_context.Extension.extension_point_loc ctxt in
50 let _method, nsid = parse_method_and_nsid ~loc str in
51+ build_call_expr ~loc nsid
5253let xrpc_extension =
54 Extension.V3.declare "xrpc" Extension.Context.expression
-11
hermes_ppx/test/test_ppx.ml
···18 let result = Hermes_ppx.nsid_to_module_path "test" in
19 check (list string) "single segment" ["Test"] result
2021-let test_build_module_path_single () =
22- let result = Hermes_ppx.build_module_path ~loc ["App"] in
23- check string "single module" "App" (Ppxlib.Longident.name result.txt)
24-25-let test_build_module_path_nested () =
26- let result = Hermes_ppx.build_module_path ~loc ["App"; "Bsky"; "Graph"] in
27- check string "nested module" "App.Bsky.Graph"
28- (Ppxlib.Longident.name result.txt)
29-30let test_build_call_expr () =
31 let result = Hermes_ppx.build_call_expr ~loc "app.bsky.graph.getProfile" in
32 let expected_str = "App.Bsky.Graph.GetProfile.call" in
···72 , `Quick
73 , test_nsid_to_module_path_camel_case )
74 ; ("nsid_to_module_path single", `Quick, test_nsid_to_module_path_single)
75- ; ("build_module_path single", `Quick, test_build_module_path_single)
76- ; ("build_module_path nested", `Quick, test_build_module_path_nested)
77 ; ("build_call_expr", `Quick, test_build_call_expr) ]
7879let expansion_tests =
···18 let result = Hermes_ppx.nsid_to_module_path "test" in
19 check (list string) "single segment" ["Test"] result
2000000000021let test_build_call_expr () =
22 let result = Hermes_ppx.build_call_expr ~loc "app.bsky.graph.getProfile" in
23 let expected_str = "App.Bsky.Graph.GetProfile.call" in
···63 , `Quick
64 , test_nsid_to_module_path_camel_case )
65 ; ("nsid_to_module_path single", `Quick, test_nsid_to_module_path_single)
0066 ; ("build_call_expr", `Quick, test_build_call_expr) ]
6768let expansion_tests =
···1-open Lexicons.Com_atproto_server_requestEmailUpdate.Main
23let request_email_update ?pending_email (actor : Data_store.Types.actor) db =
4 let token_required =
···1+open Lexicons.Com.Atproto.Server.RequestEmailUpdate.Main
23let request_email_update ?pending_email (actor : Data_store.Types.actor) db =
4 let token_required =
+1-1
pegasus/lib/api/server/requestPasswordReset.ml
···1-open Lexicons.Com_atproto_server_requestPasswordReset.Main
23let request_password_reset (actor : Data_store.Types.actor) db =
4 let did = actor.did in
···1+open Lexicons.Com.Atproto.Server.RequestPasswordReset.Main
23let request_password_reset (actor : Data_store.Types.actor) db =
4 let did = actor.did in