@@ -100,6 +100,7 @@ pub fn run_entity(name: &str, skip_confirm: bool) -> CliResult {
100100
101101 remove_from_domain_mod ( & file_name) ?;
102102 unwire_collection_from_solution ( & entity. field_name , & entity. item_type , & domain. solution_type ) ?;
103+ crate :: commands:: sf_config:: remove_entity ( & snake) ?;
103104
104105 output:: print_remove ( & format ! ( "src/domain/{}.rs" , file_name) ) ;
105106 output:: print_update ( "src/domain/mod.rs" ) ;
@@ -154,6 +155,7 @@ pub fn run_fact(name: &str, skip_confirm: bool) -> CliResult {
154155
155156 remove_from_domain_mod ( & file_name) ?;
156157 unwire_collection_from_solution ( & fact. field_name , & fact. item_type , & domain. solution_type ) ?;
158+ crate :: commands:: sf_config:: remove_fact ( & snake) ?;
157159
158160 output:: print_remove ( & format ! ( "src/domain/{}.rs" , file_name) ) ;
159161 output:: print_update ( "src/domain/mod.rs" ) ;
@@ -182,6 +184,7 @@ pub fn run_constraint(name: &str, skip_confirm: bool) -> CliResult {
182184 } ) ?;
183185
184186 remove_constraint_from_mod ( & snake) ?;
187+ crate :: commands:: sf_config:: remove_constraint ( & snake) ?;
185188
186189 output:: print_remove ( & file_path) ;
187190 output:: print_update ( "src/constraints/mod.rs" ) ;
@@ -200,15 +203,15 @@ fn remove_from_domain_mod(mod_name: &str) -> CliResult {
200203 } ) ?;
201204
202205 let lines: Vec < & str > = content. lines ( ) . collect ( ) ;
203- let mut new_lines = Vec :: new ( ) ;
206+ let mut new_lines: Vec < String > = Vec :: new ( ) ;
204207
205208 for line in lines {
206209 if line. trim ( ) == format ! ( "mod {};" , mod_name)
207210 || line. trim ( ) . starts_with ( & format ! ( "pub use {}::" , mod_name) )
208211 {
209212 continue ;
210213 }
211- new_lines. push ( line) ;
214+ new_lines. push ( line. to_string ( ) ) ;
212215 }
213216
214217 let new_content = new_lines. join ( "\n " ) ;
@@ -283,35 +286,21 @@ fn remove_constraint_from_mod(name: &str) -> CliResult {
283286 } ) ?;
284287
285288 let lines: Vec < & str > = content. lines ( ) . collect ( ) ;
286- let mut new_lines = Vec :: new ( ) ;
287- let mut in_tuple = false ;
288- let mut removed_item = false ;
289+ let mut new_lines: Vec < String > = Vec :: new ( ) ;
289290
290291 for line in lines {
291292 if line. trim ( ) == format ! ( "mod {};" , name) {
292293 continue ;
293294 }
294295
295- if line. contains ( "pub fn all() ->" ) || line. contains ( "impl Constraint" ) {
296- in_tuple = true ;
297- new_lines. push ( line) ;
298- } else if in_tuple && line. contains ( ')' ) {
299- if removed_item && !new_lines. is_empty ( ) {
300- let last_idx = new_lines. len ( ) - 1 ;
301- if let Some ( last) = new_lines. get_mut ( last_idx) {
302- if last. trim ( ) . ends_with ( ',' ) {
303- * last = last. trim ( ) . trim_end_matches ( ',' ) ;
304- }
305- }
296+ if let Some ( updated_line) = remove_constraint_call_from_line ( line, name) {
297+ if updated_line. trim ( ) . is_empty ( ) {
298+ continue ;
306299 }
307- in_tuple = false ;
308- new_lines. push ( line) ;
309- } else if in_tuple && line. contains ( & format ! ( "{}::" , name) ) {
310- removed_item = true ;
300+ new_lines. push ( updated_line) ;
311301 continue ;
312- } else {
313- new_lines. push ( line) ;
314302 }
303+ new_lines. push ( line. to_string ( ) ) ;
315304 }
316305
317306 let result = new_lines. join ( "\n " ) ;
@@ -323,3 +312,68 @@ fn remove_constraint_from_mod(name: &str) -> CliResult {
323312
324313 Ok ( ( ) )
325314}
315+
316+ fn remove_constraint_call_from_line ( line : & str , name : & str ) -> Option < String > {
317+ let needle = format ! ( "{name}::constraint()" ) ;
318+ if !line. contains ( & needle) {
319+ return None ;
320+ }
321+
322+ let indent: String = line. chars ( ) . take_while ( |c| c. is_whitespace ( ) ) . collect ( ) ;
323+ let trimmed = line. trim ( ) ;
324+ let had_trailing_comma = trimmed. ends_with ( ',' ) ;
325+ let without_trailing_comma = trimmed. trim_end_matches ( ',' ) ;
326+ let has_tuple_wrapper =
327+ without_trailing_comma. starts_with ( '(' ) && without_trailing_comma. ends_with ( ')' ) ;
328+ let inner = if has_tuple_wrapper {
329+ & without_trailing_comma[ 1 ..without_trailing_comma. len ( ) - 1 ]
330+ } else {
331+ without_trailing_comma
332+ } ;
333+
334+ let kept_parts: Vec < & str > = inner
335+ . split ( ',' )
336+ . map ( str:: trim)
337+ . filter ( |part| !part. is_empty ( ) && * part != needle)
338+ . collect ( ) ;
339+
340+ if kept_parts. is_empty ( ) {
341+ return Some ( String :: new ( ) ) ;
342+ }
343+
344+ let mut rebuilt = if has_tuple_wrapper {
345+ format ! ( "({})" , kept_parts. join( ", " ) )
346+ } else {
347+ kept_parts. join ( ", " )
348+ } ;
349+
350+ if had_trailing_comma {
351+ rebuilt. push ( ',' ) ;
352+ }
353+
354+ Some ( format ! ( "{indent}{rebuilt}" ) )
355+ }
356+
357+ #[ cfg( test) ]
358+ mod tests {
359+ use super :: remove_constraint_call_from_line;
360+
361+ #[ test]
362+ fn removes_constraint_from_multiline_tuple_entry ( ) {
363+ let line = " all_assigned::constraint()," ;
364+ let updated = remove_constraint_call_from_line ( line, "all_assigned" )
365+ . expect ( "line should be rewritten" ) ;
366+ assert ! ( updated. is_empty( ) ) ;
367+ }
368+
369+ #[ test]
370+ fn removes_constraint_from_flat_tuple_line ( ) {
371+ let line = " (capacity::constraint(), extra::constraint(), distance::constraint())" ;
372+ let updated =
373+ remove_constraint_call_from_line ( line, "extra" ) . expect ( "line should be rewritten" ) ;
374+ assert_eq ! (
375+ updated,
376+ " (capacity::constraint(), distance::constraint())"
377+ ) ;
378+ }
379+ }
0 commit comments