65 lines
1.9 KiB
Python
65 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Convert ObservableObject/@Published Swift files to imperative onChange pattern."""
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1] / "suixinkan_ios"
|
|
|
|
def convert_file(path: Path) -> bool:
|
|
text = path.read_text(encoding="utf-8")
|
|
original = text
|
|
|
|
if "ObservableObject" not in text and "@Published" not in text and "import Combine" not in text:
|
|
return False
|
|
|
|
text = re.sub(r"^import Combine\n", "", text, flags=re.MULTILINE)
|
|
|
|
if ": ObservableObject" in text:
|
|
text = text.replace(": ObservableObject", "")
|
|
# Insert onChange after class opening brace
|
|
def add_onchange(match):
|
|
decl = match.group(0)
|
|
if "onChange:" in text[match.end():match.end()+200]:
|
|
return decl
|
|
return decl + "\n var onChange: (() -> Void)?\n"
|
|
text = re.sub(
|
|
r"(final class \w+[^{]*\{)\n",
|
|
add_onchange,
|
|
text,
|
|
count=1,
|
|
)
|
|
|
|
def repl_published(m):
|
|
access = m.group(1) or ""
|
|
name = m.group(2)
|
|
rest = m.group(3)
|
|
return f"{access}var {name}{rest} {{ didSet {{ onChange?() }} }}\n"
|
|
|
|
text = re.sub(
|
|
r"@Published\s+(private\(set\)\s+)?var\s+(\w+)([^=\n]*=\s*[^\n]+)\n",
|
|
repl_published,
|
|
text,
|
|
)
|
|
text = re.sub(
|
|
r"@Published\s+(private\(set\)\s+)?var\s+(\w+)([^=\n]*)\n",
|
|
lambda m: f"{m.group(1) or ''}var {m.group(2)}{m.group(3)} {{ didSet {{ onChange?() }} }}\n",
|
|
text,
|
|
)
|
|
|
|
if text != original:
|
|
path.write_text(text, encoding="utf-8")
|
|
return True
|
|
return False
|
|
|
|
def main():
|
|
changed = 0
|
|
for path in ROOT.rglob("*.swift"):
|
|
if convert_file(path):
|
|
changed += 1
|
|
print(f"converted: {path.relative_to(ROOT.parent)}")
|
|
print(f"Done. {changed} files converted.")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|