blob: 06f222fd4b225bb56524faef277f4922a0d0073c [file] [log] [blame]
#!/usr/bin/env python3
import os, fnmatch, re, sys
#### ####
# WIP script to automagically update compose syntax.
#### ####
UI_DIRECTORY = os.path.normpath(os.path.join(os.path.dirname(__file__), "../ui"))
NO_CHILDREN_REGEX = re.compile(r"<(?P<function>[^\/\s>]+) ?(?P<parameters>[^\/>]+?)?[\s]?[\/]>", re.MULTILINE)
# Ensure no character at start to avoid matching generics like List<String>
WITH_CHILDREN_START_REGEX = re.compile(r"(?<!\w)<(?P<function>[^\/\s>]+) ?(?P<parameters>[^\/>]+?)?[\s]?(?P<end>>|(?=<))", re.MULTILINE)
WITH_CHILDREN_END_REGEX = re.compile(r"<\/[^\/\s>]+ ?>", re.MULTILINE)
# Match separate parameters separated by whitespace, unless the whitespace is between
# quotes or lambdas so we can group foo=" bar " or foo={ bar() } - use DOTALL so we can match
# multi-line lambdas like foo= {
# bar()
# }
PARAMETER_REGEX = re.compile(r'[^\s]+?["{].*?[}"]|[^\s]+', re.MULTILINE | re.DOTALL)
# Match any spaces around named parameters or lambdas for removal later to aid
# processing and ensure consistent spacing - we don't want to match whitespace
# here as that will collapse lines.
PARAMETER_SYMBOL_REGEX = re.compile(r"[ ]*([{}=])[ ]*", re.MULTILINE)
def parameter_replace(match, replacement):
total_match = match.group(0)
return total_match.replace(match.group("parameter"), replacement)
def no_child_replace(match):
function = match.group("function")
parameters = match.group("parameters")
converted_function = function + "("
if parameters:
# Replace " { " with "{" etc
parameters = re.sub(PARAMETER_SYMBOL_REGEX, r"\1", parameters)
split_parameters = re.findall(PARAMETER_REGEX, parameters)
# Add a comma to every parameter except for the last
for i in range(len(split_parameters)):
# This character breaks python regex, so if we match it in a comment just ignore it
if split_parameters[i] == "*":
continue
replacement = split_parameters[i]
# Needs to be a named parameter for now
if "=" not in replacement:
replacement += "=" + replacement
if i != len(split_parameters) - 1:
replacement += ","
# Now lets clean up spacing around braces and equals
replacement = replacement.replace("{", "{ ")
replacement = replacement.replace("}", " }")
replacement = replacement.replace("=", " = ")
# Find anything without characters on either side (we want to match 'text', and not 'textStyle')
# Then replace only the part without the spaces inside the overall match and return
parameters = re.sub(r"(^|\s)(?P<parameter>" + re.escape(split_parameters[i]) + r")($|\s)", lambda m: parameter_replace(m, replacement), parameters)
converted_function = converted_function + parameters
converted_function = converted_function + ")"
return converted_function
def with_child_replace(match):
# Hack to ignore generic parameters: 'fun <T>'
if match.group(0) == "<T>":
return match.group(0)
# If we haven't eaten a '>', it means we matched another '<' on the way, so return without
# converting the inside
if not match.group("end"):
# Return with the inside unconverted
return match.group("function") + "(" + match.group("parameters")
converted_function = no_child_replace(match)
# Remove brackets if there are no parameters
if converted_function.endswith("()"):
converted_function = converted_function[:-2]
converted_function += " {"
return converted_function
def main(args):
if len(args) != 2:
print("Usage: ./development/update_compose_syntax.py <relative/path/to/dir>")
print("Note: the path starts from the ui folder, i.e dir should look like 'material/integration-tests/material-demos'")
sys.exit(1)
directory = args[1]
directory = os.path.join(UI_DIRECTORY, directory)
for path, dirs, files in os.walk(directory):
for filename in fnmatch.filter(files, "*.kt"):
filepath = os.path.join(path, filename)
with open(filepath) as f:
content = f.read()
# Replace lambdas arrows for now as they mess with tag finding
content = content.replace("->", "~~~~")
content = re.sub(NO_CHILDREN_REGEX, no_child_replace, content)
content = re.sub(WITH_CHILDREN_START_REGEX, with_child_replace, content)
content = re.sub(WITH_CHILDREN_END_REGEX, "}", content)
# Hack because if we have nested tags and lambdas inside the parameter we can't fix the closing tag nicely
content = content.replace("}>", "}) {")
# Revert change to lambda arrows
content = content.replace("~~~~", "->")
with open(filepath, "w") as f:
f.write(content)
main(sys.argv)