-
-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Check #30 for release notes. Co-authored-by: Nathan <[email protected]> Co-authored-by: Shreyash Saitwal <[email protected]> Co-authored-by: StormiFire <[email protected]>
- Loading branch information
1 parent
26d0eda
commit 87261a1
Showing
17 changed files
with
930 additions
and
908 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
patreon: ysfchn |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,122 +1,129 @@ | ||
# -------------------------------------------- | ||
# TemplateCreator | ||
# by Yusuf Cihan | ||
# | ||
# Generates DynamicComponents-AI2 schemas by | ||
# parsing App Inventor project file automatically. | ||
# | ||
# - Yusuf Cihan | ||
# | ||
# MIT license. | ||
# -------------------------------------------- | ||
|
||
import ast | ||
from flatten_json import flatten, unflatten_list | ||
import re | ||
|
||
# Color converter | ||
def BuildColor(R : int, G : int, B : int, A : int): | ||
if A == 0: | ||
return 255 | ||
else: | ||
return (B + (G + (R + (256 * A)) * 256) * 256) - 4294967296 | ||
|
||
def GenerateTemplate(SCM : dict, extensions : dict, legacy : bool = False): | ||
import json | ||
|
||
EXTENSIONS = {} | ||
KEYS = [] | ||
|
||
# Color converter for AI2 | ||
def BuildColor(code : str): | ||
A = 255 | ||
val = str(code)[2:] | ||
if len(val) != 6: | ||
A = int(str(val)[0:2], 16) | ||
R = int(str(val)[2:4], 16) | ||
G = int(str(val)[4:6], 16) | ||
B = int(str(val)[6:], 16) | ||
return A << 24 | R << 16 | G << 8 | B | ||
|
||
|
||
def Rearrange(obj : dict): | ||
global EXTENSIONS | ||
global KEYS | ||
for key, value in obj.copy().items(): | ||
if key in obj: | ||
# If key ends with Uuid or Version, ignore it. | ||
# Because DynamicComponents-AI2 extension's JSON templates doesn't need it. | ||
if key == "Uuid" or key == "$Version": | ||
del obj[key] | ||
# Rename the $Name according to the template structure. | ||
elif key == "$Name": | ||
obj["id"] = value | ||
del obj[key] | ||
# Rename the $Type according to the template structure. | ||
elif key == "$Type": | ||
# Use the extension's full class name if it is defined in the extensions dictionary. | ||
if value in EXTENSIONS: | ||
obj["type"] = EXTENSIONS[value] | ||
del obj[key] | ||
else: | ||
obj["type"] = value | ||
del obj[key] | ||
# Rename the $Components according to the template structure. | ||
elif key == "$Components": | ||
obj["components"] = value | ||
del obj[key] | ||
# Move the properties inside a "properties" object. | ||
# components/Button/Text --> components/Button/properties/Text | ||
else: | ||
# Copy of the value for editing purposes. | ||
v = value | ||
# Create a empty dictionary named properties if doesn't exists. | ||
if "properties" not in obj: | ||
obj["properties"] = {} | ||
# Convert value to color if it presents a color code. | ||
# Colors are started with &H. | ||
if str(value).startswith("&H") and (len(str(value)) == 8 or len(str(value)) == 10): | ||
v = BuildColor(v) | ||
# Parse the values to their type automatically. | ||
# If any error raised, use the value without changing the type. | ||
try: | ||
x = ast.literal_eval(v) | ||
if key == "Text": | ||
obj["properties"][key] = str(v) | ||
else: | ||
obj["properties"][key] = x | ||
except: | ||
obj["properties"][key] = v | ||
del obj[key] | ||
# If value contains template parameters, add them to the KEYS list. | ||
if value is str: | ||
for parameter in re.findall(r'(?<=(?<!\{)\{)[^{}]*(?=\}(?!\}))', value): | ||
if parameter not in KEYS: | ||
KEYS.append(parameter) | ||
return obj | ||
|
||
|
||
def GenerateTemplate(SCM : dict, extensions : dict): | ||
# Template that will be modified later. | ||
template = { | ||
# Use app name as template name. | ||
"name": SCM["Properties"]["AppName"], | ||
|
||
# Current metadata version. | ||
# Current metadata version. | ||
# Needs to be 1, until a new type of metadata releases. | ||
"metadata-version": 1, | ||
|
||
# Extension version that this template generated for. | ||
"extension_version": 5, | ||
|
||
# Template author name. | ||
"author": "<your name>", | ||
|
||
# List of AI2 distributions that will template work on. | ||
"platforms": SCM["authURL"], | ||
|
||
# Contains used extensions in this template along with their class names. | ||
# Example: | ||
# { | ||
# "HelloWorld": "io.foo.HelloWorld" | ||
# } | ||
"extensions": extensions, | ||
|
||
# Template parameters. | ||
# Will be generated automatically from SCM. | ||
"keys": [], | ||
|
||
# Components that will be created. | ||
# Will be generated automatically from SCM. | ||
"components": [] | ||
} | ||
|
||
# Create a variable to store modified flatted JSON. | ||
flatten_json = {} | ||
|
||
# Edit the flatten JSON. | ||
for key, value in flatten(SCM["Properties"], "/").items(): | ||
k = str(key) | ||
val = value | ||
# If key ends with Uuid or Version, ignore it. | ||
# Because DynamicComponents-AI2 extension's JSON templates doesn't need it. | ||
if k.endswith("/Uuid") or k.endswith("/$Version"): | ||
continue | ||
# Else; | ||
else: | ||
# Replace the "$Components" with "components" according to the template structure. | ||
# $Components --> components | ||
k = k.replace("/$Components/", "/components/") | ||
|
||
# Rename the $Name and $Type according to the template structure. | ||
# $Name --> id | ||
# $Type --> type | ||
if k[-5:] in ["$Name", "$Type"]: | ||
k = k.replace("/$Name", "/id").replace("/$Type", "/type") | ||
# Move the properties inside a "properties" object. | ||
# components/Button/Text --> components/Button/properties/Text | ||
else: | ||
path = k.split("/") | ||
path.insert(-1, "properties") | ||
k = "/".join(path) | ||
|
||
# Check if value contains template parameter(s). | ||
# Parameters are defined with curly brackets. | ||
# {text}, {age}, {color} | ||
for parameter in re.findall(r'(?<=(?<!\{)\{)[^{}]*(?=\}(?!\}))', str(value) + " " + k): | ||
if parameter not in template["keys"]: | ||
template["keys"].append(parameter) | ||
|
||
# Try to convert the value automatically. | ||
# So if value is "True" or "False", then it will be converted to the bool and so on. | ||
try: | ||
val = ast.literal_eval(value) | ||
except: | ||
pass | ||
|
||
# An exception for the color converting. | ||
if str(val).startswith("&H"): | ||
val = str(val)[2:] | ||
if len(val) == 6: | ||
alpha = int("FF", 16) | ||
else: | ||
alpha = int(str(val)[0:2], 16) | ||
val = BuildColor(int(str(val)[2:4], 16), int(str(val)[4:6], 16), int(str(val)[6:], 16), alpha) | ||
|
||
# If the component name is in the extensions list, | ||
# then use its full internal name as it is an external package that | ||
# doesn't exists in the App Inventor sources. | ||
if k.endswith("/type") and (val in extensions): | ||
val = extensions[val] | ||
|
||
# Add the value and key to the modified flatten dictionary. | ||
flatten_json[k] = val | ||
|
||
# Now, unflat the modified flatten dictionary. | ||
# Save the output to the template. | ||
template["components"] = unflatten_list(flatten_json, "/")["$Components"] | ||
|
||
# Remove DynamicComponent instances from template, because it is not needed. | ||
global EXTENSIONS | ||
global KEYS | ||
# Save extensions in the list. | ||
EXTENSIONS = extensions | ||
# Convert SCM data to Dynamic Components schema data. | ||
template["components"] = json.loads(json.dumps(SCM), object_hook = Rearrange)["properties"]["Properties"]["components"] | ||
# Save found keys in the template. | ||
template["keys"] = KEYS | ||
# Remove DynamicComponent instances from template, because they are not needed. | ||
for component in template["components"].copy(): | ||
if component["type"] == "DynamicComponents": | ||
if component in template["components"]: | ||
template["components"].remove(component) | ||
|
||
# Return the template. | ||
return template |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.