@@ -29,6 +29,171 @@ static char* extract_string_from_prism_node(pm_node_t* node, hb_allocator_T* all
2929 return hb_allocator_strndup (allocator , (const char * ) source , length );
3030}
3131
32+ static void compute_position_pair (
33+ const pm_location_t * location ,
34+ const uint8_t * source ,
35+ const char * original_source ,
36+ size_t erb_content_offset ,
37+ position_T * out_start ,
38+ position_T * out_end
39+ ) {
40+ * out_start = prism_location_to_position_with_offset (location , original_source , erb_content_offset , source );
41+ pm_location_t end_location = { .start = location -> end , .end = location -> end };
42+ * out_end = prism_location_to_position_with_offset (& end_location , original_source , erb_content_offset , source );
43+ }
44+
45+ static void extract_key_name_location (pm_node_t * key , pm_location_t * out_name_loc ) {
46+ if (key -> type == PM_SYMBOL_NODE ) {
47+ pm_symbol_node_t * symbol = (pm_symbol_node_t * ) key ;
48+ * out_name_loc = symbol -> value_loc ;
49+ } else if (key -> type == PM_STRING_NODE ) {
50+ pm_string_node_t * string_node = (pm_string_node_t * ) key ;
51+ * out_name_loc = string_node -> content_loc ;
52+ } else {
53+ * out_name_loc = key -> location ;
54+ }
55+ }
56+
57+ static void compute_separator_info (
58+ pm_assoc_node_t * assoc ,
59+ const uint8_t * source ,
60+ const char * original_source ,
61+ size_t erb_content_offset ,
62+ position_T key_end ,
63+ const char * * out_separator_string ,
64+ token_type_T * out_separator_type ,
65+ position_T * out_separator_start ,
66+ position_T * out_separator_end
67+ ) {
68+ * out_separator_end =
69+ prism_location_to_position_with_offset (& assoc -> value -> location , original_source , erb_content_offset , source );
70+
71+ if (assoc -> operator_loc .start != NULL ) {
72+ * out_separator_string = " => " ;
73+ * out_separator_type = TOKEN_EQUALS ;
74+ * out_separator_start = key_end ;
75+ } else {
76+ * out_separator_string = ": " ;
77+ * out_separator_type = TOKEN_COLON ;
78+
79+ pm_location_t colon_loc = {
80+ .start = assoc -> key -> location .end - 1 ,
81+ .end = assoc -> key -> location .end - 1 ,
82+ };
83+
84+ * out_separator_start =
85+ prism_location_to_position_with_offset (& colon_loc , original_source , erb_content_offset , source );
86+ }
87+ }
88+
89+ static void extract_delimited_locations (
90+ pm_node_t * node ,
91+ const pm_location_t * * out_opening ,
92+ const pm_location_t * * out_closing ,
93+ const pm_location_t * * out_content
94+ ) {
95+ if (node -> type == PM_STRING_NODE ) {
96+ pm_string_node_t * string_node = (pm_string_node_t * ) node ;
97+ * out_opening = & string_node -> opening_loc ;
98+ * out_closing = & string_node -> closing_loc ;
99+ * out_content = & string_node -> content_loc ;
100+ } else if (node -> type == PM_SYMBOL_NODE ) {
101+ pm_symbol_node_t * symbol_node = (pm_symbol_node_t * ) node ;
102+ * out_opening = & symbol_node -> opening_loc ;
103+ * out_closing = & symbol_node -> closing_loc ;
104+ * out_content = & symbol_node -> value_loc ;
105+ } else {
106+ * out_opening = NULL ;
107+ * out_closing = NULL ;
108+ * out_content = NULL ;
109+ }
110+ }
111+
112+ static void compute_value_positions (
113+ pm_node_t * value_node ,
114+ const uint8_t * source ,
115+ const char * original_source ,
116+ size_t erb_content_offset ,
117+ position_T * out_value_start ,
118+ position_T * out_value_end ,
119+ position_T * out_content_start ,
120+ position_T * out_content_end ,
121+ bool * out_quoted
122+ ) {
123+ const pm_location_t * opening_loc ;
124+ const pm_location_t * closing_loc ;
125+ const pm_location_t * content_loc ;
126+
127+ extract_delimited_locations (value_node , & opening_loc , & closing_loc , & content_loc );
128+
129+ if (opening_loc && opening_loc -> start != NULL && closing_loc && closing_loc -> start != NULL ) {
130+ compute_position_pair (
131+ & * opening_loc ,
132+ source ,
133+ original_source ,
134+ erb_content_offset ,
135+ out_value_start ,
136+ out_content_start
137+ );
138+
139+ compute_position_pair (& * closing_loc , source , original_source , erb_content_offset , out_content_end , out_value_end );
140+ * out_quoted = true;
141+ } else {
142+ const pm_location_t * fallback_loc = content_loc ? content_loc : & value_node -> location ;
143+ compute_position_pair (fallback_loc , source , original_source , erb_content_offset , out_value_start , out_value_end );
144+ * out_content_start = * out_value_start ;
145+ * out_content_end = * out_value_end ;
146+ * out_quoted = false;
147+ }
148+ }
149+
150+ static void fill_attribute_positions (
151+ pm_assoc_node_t * assoc ,
152+ const uint8_t * source ,
153+ const char * original_source ,
154+ size_t erb_content_offset ,
155+ attribute_positions_T * positions
156+ ) {
157+ pm_location_t name_loc ;
158+ extract_key_name_location (assoc -> key , & name_loc );
159+ compute_position_pair (
160+ & name_loc ,
161+ source ,
162+ original_source ,
163+ erb_content_offset ,
164+ & positions -> name_start ,
165+ & positions -> name_end
166+ );
167+
168+ position_T key_end ;
169+ pm_location_t key_end_loc = { .start = assoc -> key -> location .end , .end = assoc -> key -> location .end };
170+ key_end = prism_location_to_position_with_offset (& key_end_loc , original_source , erb_content_offset , source );
171+
172+ compute_separator_info (
173+ assoc ,
174+ source ,
175+ original_source ,
176+ erb_content_offset ,
177+ key_end ,
178+ & positions -> separator_string ,
179+ & positions -> separator_type ,
180+ & positions -> separator_start ,
181+ & positions -> separator_end
182+ );
183+
184+ compute_value_positions (
185+ assoc -> value ,
186+ source ,
187+ original_source ,
188+ erb_content_offset ,
189+ & positions -> value_start ,
190+ & positions -> value_end ,
191+ & positions -> content_start ,
192+ & positions -> content_end ,
193+ & positions -> quoted
194+ );
195+ }
196+
32197static char * build_prefixed_key (const char * prefix , const char * raw_key , hb_allocator_T * allocator ) {
33198 char * dashed_key = convert_underscores_to_dashes (raw_key );
34199 const char * key = dashed_key ? dashed_key : raw_key ;
@@ -46,33 +211,32 @@ static char* build_prefixed_key(const char* prefix, const char* raw_key, hb_allo
46211static AST_HTML_ATTRIBUTE_NODE_T * create_attribute_from_value (
47212 const char * name_string ,
48213 pm_node_t * value_node ,
49- position_T start_position ,
50- position_T end_position ,
214+ attribute_positions_T * positions ,
51215 hb_allocator_T * allocator
52216) {
53217 if (value_node -> type == PM_SYMBOL_NODE || value_node -> type == PM_STRING_NODE ) {
54218 char * value_string = extract_string_from_prism_node (value_node , allocator );
55219 if (!value_string ) { return NULL ; }
56220
57221 AST_HTML_ATTRIBUTE_NODE_T * attribute =
58- create_html_attribute_node (name_string , value_string , start_position , end_position , allocator );
222+ create_html_attribute_node_precise (name_string , value_string , positions , allocator );
59223 hb_allocator_dealloc (allocator , value_string );
60224
61225 return attribute ;
62226 } else if (value_node -> type == PM_TRUE_NODE ) {
63227 if (is_boolean_attribute (hb_string ((char * ) name_string ))) {
64- return create_html_attribute_node (name_string , NULL , start_position , end_position , allocator );
228+ return create_html_attribute_node_precise (name_string , NULL , positions , allocator );
65229 }
66- return create_html_attribute_node (name_string , "true" , start_position , end_position , allocator );
230+ return create_html_attribute_node_precise (name_string , "true" , positions , allocator );
67231 } else if (value_node -> type == PM_FALSE_NODE ) {
68232 if (is_boolean_attribute (hb_string ((char * ) name_string ))) { return NULL ; }
69- return create_html_attribute_node (name_string , "false" , start_position , end_position , allocator );
233+ return create_html_attribute_node_precise (name_string , "false" , positions , allocator );
70234 } else if (value_node -> type == PM_INTERPOLATED_STRING_NODE ) {
71235 return create_html_attribute_with_interpolated_value (
72236 name_string ,
73237 (pm_interpolated_string_node_t * ) value_node ,
74- start_position ,
75- end_position ,
238+ positions -> name_start ,
239+ positions -> value_end ,
76240 allocator
77241 );
78242 } else {
@@ -81,7 +245,7 @@ static AST_HTML_ATTRIBUTE_NODE_T* create_attribute_from_value(
81245
82246 if (ruby_content && value_node -> location .start ) {
83247 AST_HTML_ATTRIBUTE_NODE_T * attribute =
84- create_html_attribute_with_ruby_literal (name_string , ruby_content , start_position , end_position , allocator );
248+ create_html_attribute_with_ruby_literal_precise (name_string , ruby_content , positions , allocator );
85249 hb_allocator_dealloc (allocator , ruby_content );
86250 return attribute ;
87251 }
@@ -102,23 +266,24 @@ AST_HTML_ATTRIBUTE_NODE_T* extract_html_attribute_from_assoc(
102266 char * name_string = extract_string_from_prism_node (assoc -> key , allocator );
103267 if (!name_string ) { return NULL ; }
104268
105- position_T start_position =
106- prism_location_to_position_with_offset (& assoc -> key -> location , original_source , erb_content_offset , source );
107-
108269 if (!assoc -> value ) {
109270 hb_allocator_dealloc (allocator , name_string );
110-
111271 return NULL ;
112272 }
113273
114274 if (assoc -> value -> type == PM_IMPLICIT_NODE ) {
275+ pm_location_t name_loc ;
276+ extract_key_name_location (assoc -> key , & name_loc );
277+ position_T name_start , name_end ;
278+ compute_position_pair (& name_loc , source , original_source , erb_content_offset , & name_start , & name_end );
279+
115280 char * dashed_name = convert_underscores_to_dashes (name_string );
116281
117282 AST_HTML_ATTRIBUTE_NODE_T * attribute = create_html_attribute_with_ruby_literal (
118283 dashed_name ? dashed_name : name_string ,
119284 name_string ,
120- start_position ,
121- start_position ,
285+ name_start ,
286+ name_start ,
122287 allocator
123288 );
124289
@@ -128,9 +293,6 @@ AST_HTML_ATTRIBUTE_NODE_T* extract_html_attribute_from_assoc(
128293 return attribute ;
129294 }
130295
131- position_T end_position =
132- prism_location_to_position_with_offset (& assoc -> value -> location , original_source , erb_content_offset , source );
133-
134296 // Rails converts `method:` and `remote:` to `data-*` attributes
135297 if (strcmp (name_string , "method" ) == 0 || strcmp (name_string , "remote" ) == 0 ) {
136298 size_t name_len = strlen (name_string );
@@ -146,14 +308,12 @@ AST_HTML_ATTRIBUTE_NODE_T* extract_html_attribute_from_assoc(
146308 return NULL ;
147309 }
148310
311+ attribute_positions_T positions ;
312+ fill_attribute_positions (assoc , source , original_source , erb_content_offset , & positions );
313+
149314 char * dashed_name = convert_underscores_to_dashes (name_string );
150- AST_HTML_ATTRIBUTE_NODE_T * attribute_node = create_attribute_from_value (
151- dashed_name ? dashed_name : name_string ,
152- assoc -> value ,
153- start_position ,
154- end_position ,
155- allocator
156- );
315+ AST_HTML_ATTRIBUTE_NODE_T * attribute_node =
316+ create_attribute_from_value (dashed_name ? dashed_name : name_string , assoc -> value , & positions , allocator );
157317
158318 if (dashed_name ) { free (dashed_name ); }
159319 hb_allocator_dealloc (allocator , name_string );
@@ -251,26 +411,11 @@ hb_array_T* extract_html_attributes_from_keyword_hash(
251411 hb_allocator_dealloc (allocator , raw_key );
252412
253413 if (attribute_key_string ) {
254- position_T attribute_start = prism_location_to_position_with_offset (
255- & hash_assoc -> key -> location ,
256- original_source ,
257- erb_content_offset ,
258- source
259- );
260- position_T attribute_end = prism_location_to_position_with_offset (
261- & hash_assoc -> value -> location ,
262- original_source ,
263- erb_content_offset ,
264- source
265- );
266-
267- AST_HTML_ATTRIBUTE_NODE_T * attribute = create_attribute_from_value (
268- attribute_key_string ,
269- hash_assoc -> value ,
270- attribute_start ,
271- attribute_end ,
272- allocator
273- );
414+ attribute_positions_T hash_positions ;
415+ fill_attribute_positions (hash_assoc , source , original_source , erb_content_offset , & hash_positions );
416+
417+ AST_HTML_ATTRIBUTE_NODE_T * attribute =
418+ create_attribute_from_value (attribute_key_string , hash_assoc -> value , & hash_positions , allocator );
274419
275420 if (attribute ) { hb_array_append (attributes , attribute ); }
276421 hb_allocator_dealloc (allocator , attribute_key_string );
0 commit comments