Files
Finlytic/FinlyticFundamentals/refactor.py
T

118 lines
5.3 KiB
Python

import os
import re
def process_file(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
# 1. Update logger statements
# We want to match: _logger.LogInformation("something", args) or _logger.LogError(ex, "something", args)
# This regex is a bit tricky, let's use a simpler approach or careful regex.
# Pattern to match logger.Log...( optionally (ex, ) then string then args )
# Let's match: (logger\.Log[A-Za-z]+)\((.*?)"(.*?)"(.*?)\)
# Wait, multi-line strings or strings with escaped quotes might break it.
# The regex approach:
# Match: (logger\.Log(?:Information|Warning|Error))\(([^"]*)"([^"]*)"(.*)\)
# If the string already starts with "[{Channel}] ", skip it.
def replacer(m):
func_part = m.group(1) # e.g. _logger.LogInformation
pre_str = m.group(2) # e.g. (ex, or empty if it's the first arg)
msg_str = m.group(3)
post_str = m.group(4)
if "[{Channel}]" in msg_str:
return m.group(0)
new_msg = f"[{{Channel}}] {msg_str}"
# append "FundamentalsChannel" as the first argument after the string, or right after if there are no args
if post_str.strip().startswith(','):
# args exist, we need to insert our channel arg before the existing ones, but wait, the channel arg corresponds to {Channel} which is FIRST in the string, so we must pass "FundamentalsChannel" as the FIRST format argument.
new_post = f', "FundamentalsChannel"{post_str}'
elif post_str.strip() == '':
# no extra args, just the closing paren
new_post = f', "FundamentalsChannel")'
# Note: m.group(4) didn't include the closing paren if we don't match it. Let's adjust the regex to match up to closing paren.
else:
new_post = f', "FundamentalsChannel"{post_str}'
return f'{func_part}({pre_str}"{new_msg}"{new_post}'
# Regex to capture the parts.
# group 1: logger.Log...
# group 2: anything before the first quote (like exception)
# group 3: the string itself
# group 4: the rest of the arguments up to the closing parenthesis
# We need to find all instances. Let's do a line-by-line or simple regex.
lines = content.split('\n')
new_lines = []
# 2. Add /// <summary> to public methods
# Method pattern: public (async )?(Task|void|[A-Za-z0-9_<>]+) [A-Za-z0-9_]+\(.*\)
method_pattern = re.compile(r'^\s*public\s+(?:async\s+)?[A-Za-z0-9_<>\[\]]+\s+[A-Za-z0-9_]+\(.*')
for i, line in enumerate(lines):
# Apply logger transformation
# We look for _logger.LogInformation, _logger.LogWarning, _logger.LogError, logger.LogError etc.
if '.LogInformation(' in line or '.LogWarning(' in line or '.LogError(' in line:
# simple replacement logic
match = re.search(r'([_a-zA-Z0-9]+\.Log(?:Information|Warning|Error))\(([^"]*)"(.*?)"(.*)\)', line)
if match:
func_part = match.group(1)
pre_str = match.group(2)
msg_str = match.group(3)
post_str = match.group(4)
if "[{Channel}]" not in msg_str:
new_msg = f"[{{Channel}}] {msg_str}"
if post_str.strip() == ')':
new_post = ', "FundamentalsChannel")'
elif post_str.endswith(');'):
new_post = ', "FundamentalsChannel");'
# strip the ); from post_str for clean insertion
post_str = post_str[:-2]
new_post = f', "FundamentalsChannel"{post_str});'
else:
new_post = f', "FundamentalsChannel"{post_str}'
line = f'{line[:match.start()]}{func_part}({pre_str}"{new_msg}"{new_post}{line[match.end():]}'
# Check for public method to add /// <summary>
# We need to make sure we don't add it if it already has one.
# Also interface methods: Task<string> Something();
if method_pattern.match(line):
# Check previous line
if i > 0 and '///' not in lines[i-1] and '[' not in lines[i-1]:
indent = len(line) - len(line.lstrip())
summary = ' ' * indent + '/// <summary>\n' + ' ' * indent + '/// \n' + ' ' * indent + '/// </summary>'
new_lines.append(summary)
# Interface methods inside public interface
if re.match(r'^\s*(?:Task|void|[A-Za-z0-9_<>\[\]]+)\s+[A-Za-z0-9_]+\(.*', line):
if i > 0 and '///' not in lines[i-1] and '[' not in lines[i-1]:
# check if we are in an interface
# kinda hard with just line by line, but let's try.
pass
new_lines.append(line)
with open(filepath, 'w', encoding='utf-8') as f:
f.write('\n'.join(new_lines))
def main():
dirs = ['Services', 'Util', '.']
base = r'e:\Projects\Finlytic\FinlyticFundamentals'
for d in dirs:
p = os.path.join(base, d)
if os.path.isdir(p):
for file in os.listdir(p):
if file.endswith('.cs'):
filepath = os.path.join(p, file)
process_file(filepath)
if __name__ == "__main__":
main()