-
Notifications
You must be signed in to change notification settings - Fork 13
/
migrate.py
124 lines (104 loc) · 3.83 KB
/
migrate.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import re
import sys
from pathlib import Path
class Migrate:
preserve_detectors = [
r'([\s]+)?\*\s@deprecated$',
]
remove_detectors = [
r'([\s]+)?\*\s@[\S]+$',
r'([\s]+)?\*\s@[\w]+\s[\S]+$',
]
function_detectors = [
r'.*function\s?\(.*'
]
untyped_detectors = [
r'(.*(?:const|let)\s?)([\w]+)(\s?=.*)'
]
def __init__(self, path: Path):
self.path = path
def read(self) -> str:
with self.path.open() as source_file:
contents = source_file.read()
return contents
def write(self, contents: str) -> int:
return self.path.write_text(contents)
def preserve(self, content: str) -> list:
return [re.fullmatch(detector, content) for detector in self.preserve_detectors]
def remove(self, content: str) -> list:
return [re.fullmatch(detector, content) for detector in self.remove_detectors]
def skip(self, content: str) -> bool:
return any(self.remove(content)) and not any(self.preserve(content))
def convert(self, content: str) -> str:
# upgrade to arrow functions
if any([re.fullmatch(detector, content) for detector in self.function_detectors]):
m = re.fullmatch(r'(.*)function\s?\(((?:[\w\s:,]+)?)?\)\s?{(.*)', content)
if m is None:
return content
g = m.groups()
d = ', '
return g[0] + '(' + d.join([x + ': any' for x in g[1].split(d)]) + ') => {' + g[2]
# add types to var declarations
untyped_var = re.fullmatch(r'(.*(?:const|let)\s?[\w]+)(\s?=.*)', content)
if untyped_var:
g = untyped_var.groups()
return g[0] + ': any' + g[1]
# add types to function declarations
untyped_function = re.fullmatch(
r'((?:[\s]+)?(?!if|else|switch)(?:[\w]+)(?:[\s]+)?\()((?:[\w\s:,]+)?)(\)(?:[\s]+)?{(?:[\s]+)?)',
content)
if untyped_function:
g = untyped_function.groups()
d = ', '
return g[0] + d.join([x if ':' in x or not len(x) else x + ': any' for x in g[1].split(d)]) + g[2]
return content
def shift(self, contents: str) -> str:
lines = []
d = '\n'
return d.join([self.convert(x) for x in contents.split(d) if not self.skip(x)])
def test():
# tests
tests = {
'* @foo': True,
' * @foo': True,
'* @foo {bar}': True,
' * @foo {bar}': True,
'* @foo {bar} baz': False,
' * @foo {bar} baz': False,
}
migrate = Migrate(Path('.'))
print(migrate.convert(' listen(options) {'))
for instance, value in tests.items():
results = migrate.remove(instance)
if any(results) != value:
print('failed:', results)
def main():
import argparse
# settings
parser = argparse.ArgumentParser(description='TypeScript Migrations')
parser.add_argument('-v', '--version', dest='version', action='version', version='1.0')
parser.add_argument('targets', metavar='t', type=str, nargs='+', help='target(s) to migrate')
# parse
args = parser.parse_args()
for target in args.targets:
path = Path(target)
if not path.is_file():
raise ValueError(f'Path: {target} does not exist!')
migrate_test = Migrate(path)
print('file:', target)
# changing = True
# while changing:
data = migrate_test.read()
print('size:', sys.getsizeof(data), 'bytes')
converted = migrate_test.shift(data)
if data == converted:
print('status: nothing changed!')
continue
migrate_test.write(converted)
print('wrote:', sys.getsizeof(converted), 'bytes')
# changing = False
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print('\nGoodbye!')