package utils import ( "fmt" "sort" logger "git.site.quack-lab.dev/dave/cylogger" ) // replaceCommandLogger is a scoped logger for the utils/replacecommand package. var replaceCommandLogger = logger.Default.WithPrefix("utils/replacecommand") type ReplaceCommand struct { From int To int With string } func ExecuteModifications(modifications []ReplaceCommand, fileData string) (string, int) { executeModificationsLogger := replaceCommandLogger.WithPrefix("ExecuteModifications") executeModificationsLogger.Debug("Executing a batch of text modifications") executeModificationsLogger.Trace("Number of modifications: %d, Original file data length: %d", len(modifications), len(fileData)) var err error sort.Slice(modifications, func(i, j int) bool { return modifications[i].From > modifications[j].From }) executeModificationsLogger.Debug("Modifications sorted in reverse order for safe replacement") executeModificationsLogger.Trace("Sorted modifications: %v", modifications) executed := 0 for idx, modification := range modifications { executeModificationsLogger.Debug("Applying modification %d/%d", idx+1, len(modifications)) executeModificationsLogger.Trace("Current modification details: From=%d, To=%d, With=%q", modification.From, modification.To, modification.With) fileData, err = modification.Execute(fileData) if err != nil { executeModificationsLogger.Error("Failed to execute replacement for modification %+v: %v", modification, err) continue } executed++ executeModificationsLogger.Trace("File data length after modification: %d", len(fileData)) } executeModificationsLogger.Info("Successfully applied %d text replacements", executed) return fileData, executed } func (m *ReplaceCommand) Execute(fileDataStr string) (string, error) { executeLogger := replaceCommandLogger.WithPrefix("Execute").WithField("modification", fmt.Sprintf("From:%d,To:%d,With:%q", m.From, m.To, m.With)) executeLogger.Debug("Attempting to execute single replacement") err := m.Validate(len(fileDataStr)) if err != nil { executeLogger.Error("Failed to validate modification: %v", err) return fileDataStr, fmt.Errorf("failed to validate modification: %v", err) } executeLogger.Trace("Applying replacement: fileDataStr[:%d] + %q + fileDataStr[%d:]", m.From, m.With, m.To) result := fileDataStr[:m.From] + m.With + fileDataStr[m.To:] executeLogger.Trace("Replacement executed. Result length: %d", len(result)) return result, nil } func (m *ReplaceCommand) Validate(maxsize int) error { validateLogger := replaceCommandLogger.WithPrefix("Validate").WithField("modification", fmt.Sprintf("From:%d,To:%d,With:%q", m.From, m.To, m.With)).WithField("maxSize", maxsize) validateLogger.Debug("Validating replacement command against max size") if m.To < m.From { validateLogger.Error("Validation failed: 'To' (%d) is less than 'From' (%d)", m.To, m.From) return fmt.Errorf("command to is less than from: %v", m) } if m.From > maxsize || m.To > maxsize { validateLogger.Error("Validation failed: 'From' (%d) or 'To' (%d) is greater than max size (%d)", m.From, m.To, maxsize) return fmt.Errorf("command from or to is greater than replacement length: %v", m) } if m.From < 0 || m.To < 0 { validateLogger.Error("Validation failed: 'From' (%d) or 'To' (%d) is less than 0", m.From, m.To) return fmt.Errorf("command from or to is less than 0: %v", m) } validateLogger.Debug("Modification command validated successfully") return nil }