@@ -58,14 +58,46 @@ let payload_to_data (payload : Ast_payload.t) :
5858 match e.pexp_desc with
5959 | Pexp_constant (Pconst_string (txt , _ )) ->
6060 Some (Ext_json_noloc. str txt, e.pexp_loc)
61- | _ -> (
61+ | Pexp_record _ -> (
6262 match expr_to_json e with
6363 | Some json -> Some (json, e.pexp_loc)
64- | None -> None ))
64+ | None -> None )
65+ | _ -> None )
6566 | _ -> None
6667
68+ let validate_id_in_payload (payload : Ast_payload.t ) : unit =
69+ match payload with
70+ | PStr [{pstr_desc = Pstr_eval (e, _attrs); _}] -> (
71+ match e.pexp_desc with
72+ | Pexp_record (fields , None) ->
73+ let found = ref false in
74+ let rec find = function
75+ | [] ->
76+ if not ! found then
77+ Location. raise_errorf ~loc: e.pexp_loc " %s"
78+ Ext_embed. missing_id_error_message
79+ | ({lid; x = v; _} : Parsetree.expression Parsetree.record_element )
80+ :: rest ->
81+ let name = String. concat " ." (Longident. flatten lid.txt) in
82+ if name = " id" then
83+ match v.pexp_desc with
84+ | Pexp_constant (Pconst_string (s , _ )) ->
85+ found := true ;
86+ if not (Ext_embed. is_valid_embed_id s) then
87+ Location. raise_errorf ~loc: v.pexp_loc " %s"
88+ Ext_embed. invalid_id_error_message
89+ | _ ->
90+ Location. raise_errorf ~loc: v.pexp_loc " %s"
91+ Ext_embed. missing_id_error_message
92+ else find rest
93+ in
94+ find fields
95+ | _ -> () )
96+ | _ -> ()
97+
6798let write_structure_index ~outprefix ~sourcefile (ast : structure ) : unit =
6899 if is_enabled () then (
100+ let modulename = Ext_filename. module_name outprefix in
69101 let entries = ref [] in
70102 let counts : (string, int) Hashtbl.t = Hashtbl. create 7 in
71103 let bump tag =
@@ -87,10 +119,29 @@ let write_structure_index ~outprefix ~sourcefile (ast : structure) : unit =
87119 | _ -> Ext_json_noloc. to_string data
88120 in
89121 let literal_hash = csv_hash tag data_str in
122+ let tag_normalized = Ext_embed. normalize_tag_for_symbol tag in
123+ let suffix =
124+ match data with
125+ | Ext_json_noloc. Str _ -> string_of_int occurrence_index
126+ | Ext_json_noloc. Obj map -> (
127+ match Map_string. find_opt map " id" with
128+ | Some (Ext_json_noloc. Str s ) -> s
129+ | _ ->
130+ (* Should be prevented by earlier validation *)
131+ Location. raise_errorf ~loc " %s"
132+ Ext_embed. missing_id_error_message)
133+ | _ ->
134+ Location. raise_errorf ~loc " %s"
135+ Ext_embed. invalid_payload_error_message
136+ in
137+ let target_module =
138+ Printf. sprintf " %s__embed_%s_%s" modulename tag_normalized suffix
139+ in
90140 let entry =
91141 Ext_json_noloc. kvs
92142 [
93143 (" tag" , Ext_json_noloc. str tag);
144+ (" targetModule" , Ext_json_noloc. str target_module);
94145 (" context" , Ext_json_noloc. str context);
95146 ( " occurrenceIndex" ,
96147 Ext_json_noloc. flo (string_of_int occurrence_index) );
@@ -101,7 +152,7 @@ let write_structure_index ~outprefix ~sourcefile (ast : structure) : unit =
101152 in
102153 entries := entry :: ! entries
103154 in
104- let normalize_tag (tag : string ) : string =
155+ let base_tag_of_extension (tag : string ) : string =
105156 match Ext_embed. get_embed_tag tag with
106157 | Some t -> t
107158 | None -> tag
@@ -124,19 +175,18 @@ let write_structure_index ~outprefix ~sourcefile (ast : structure) : unit =
124175 (fun self m ->
125176 (match m.pmod_desc with
126177 | Pmod_extension ({txt = tag ; _} , payload ) ->
127- let base_tag = normalize_tag tag in
128- if should_collect_tag base_tag then
178+ let base_tag = base_tag_of_extension tag in
179+ if should_collect_tag base_tag then (
180+ validate_id_in_payload payload;
129181 match payload_to_data payload with
130182 | Some (data , loc ) ->
131183 let context =
132184 Option. value ~default: " module" ! current_mod_context
133185 in
134186 add_entry ~tag: base_tag ~context ~data ~loc
135187 | None ->
136- Location. raise_errorf ~loc: m.pmod_loc
137- " %%%s expects a string literal or a JSON-serializable \
138- record literal"
139- tag
188+ Location. raise_errorf ~loc: m.pmod_loc " %s"
189+ Ext_embed. invalid_payload_error_message)
140190 else ()
141191 | _ -> () );
142192 let prev = ! current_mod_context in
@@ -161,16 +211,15 @@ let write_structure_index ~outprefix ~sourcefile (ast : structure) : unit =
161211 (fun self e ->
162212 (match e.pexp_desc with
163213 | Pexp_extension ({txt = tag ; _} , payload ) ->
164- let base_tag = normalize_tag tag in
165- if should_collect_tag base_tag then
214+ let base_tag = base_tag_of_extension tag in
215+ if should_collect_tag base_tag then (
216+ validate_id_in_payload payload;
166217 match payload_to_data payload with
167218 | Some (data , loc ) ->
168219 add_entry ~tag: base_tag ~context: " expr" ~data ~loc
169220 | None ->
170- Location. raise_errorf ~loc: e.pexp_loc
171- " %%%s expects a string literal or a JSON-serializable \
172- record literal"
173- tag
221+ Location. raise_errorf ~loc: e.pexp_loc " %s"
222+ Ext_embed. invalid_payload_error_message)
174223 else ()
175224 | _ -> () );
176225 default_it.expr self e);
@@ -180,7 +229,6 @@ let write_structure_index ~outprefix ~sourcefile (ast : structure) : unit =
180229 let entries_json =
181230 ! entries |> List. rev |> Array. of_list |> Ext_json_noloc. arr
182231 in
183- let modulename = Ext_filename. module_name outprefix in
184232 let source_path = sourcefile in
185233 let json =
186234 Ext_json_noloc. kvs
0 commit comments