-
Notifications
You must be signed in to change notification settings - Fork 0
/
component_hinting_helper.py
141 lines (122 loc) · 5.55 KB
/
component_hinting_helper.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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import argparse
import json
from pathlib import Path
from typing import Any
import jinjax
def find_textmate_rule_string_position(vscode_settings: str, textmate_rule_name: str) -> tuple[int, int, int] | None:
# TODO: This is naive, it doesn't handle the textmate rule not existing
# I just really wanted to keep formatting T.T
current_object_starts = []
in_string = False
for i, char in enumerate(vscode_settings):
if char == '"':
in_string = not in_string
if char == "{" and not in_string:
current_object_starts.append(i)
elif char == "}" and not in_string:
start = current_object_starts.pop()
# print(f"Found object: {vscode_settings[start : i + 1]}")
try:
parsed_object: dict[str, Any] = json.loads(vscode_settings[start : i + 1])
except json.JSONDecodeError:
# print(f"Failed to parse object: {vscode_settings[start : i + 1]}")
continue
if parsed_object.get("name") == textmate_rule_name:
# print(f"Found textmate rule: {parsed_object}")
required_indentation = 0
j = start - 1
while vscode_settings[j] == " ":
required_indentation += 1
j -= 1
return start, i, required_indentation
return None
def main(args: argparse.Namespace):
component_directory: Path = args.component_directory
file_patterns: list[str] = args.file_patterns
textmate_rule_name: str = args.textmate_rule_name
token_color: str = args.token_color
custom_data_file: Path = args.custom_data_file
vscode_settings_path: Path = args.vscode_settings_path
add_vscode_settings: bool = args.add_vscode_settings
custom_data_tags: list[dict[str, Any]] = []
component_names: set[str] = set()
for path in set().union(*(component_directory.rglob(pattern) for pattern in file_patterns)):
relative_parent = path.parent.relative_to(component_directory).parts
stem = path.name[: -len("".join(path.suffixes))]
name = ".".join(relative_parent + (stem,))
component = jinjax.Component(name=name, path=path)
print(f"Loaded component: {component.name}")
component_description_lines = [f"**Component:** {component.name}"]
if component.required:
required_list = "\n".join([f" - {arg}" for arg in component.required])
component_description_lines.append(f"**Requires:**\n{required_list}")
if component.optional:
optional_list = "\n".join([f" - {arg}" for arg in component.optional])
component_description_lines.append(f"**Optional:**\n{optional_list}")
custom_data_tags.append(
{
"name": component.name,
"description": {
"kind": "markdown",
"value": "\n\n".join(component_description_lines),
},
"references": [{"name": "Source", "url": f"file://{str(path.resolve())}"}],
"attributes": [
{
"name": arg,
"description": f"Required attribute {arg}",
}
for arg in component.required
]
+ [
{
"name": arg,
"description": f"Optional attribute {arg}",
}
for arg in component.optional
],
}
)
component_names.add(component.name)
custom_data = {
"version": 1.1,
"tags": custom_data_tags,
}
with open(custom_data_file, "w") as f:
json.dump(custom_data, f, indent=4)
if add_vscode_settings:
textmate_rule = {
"scope": [
f"meta.tag.other.{component_name}.html invalid.illegal.unrecognized-tag.html"
for component_name in sorted(component_names)
],
"name": textmate_rule_name,
"settings": {
"foreground": token_color,
},
}
with open(vscode_settings_path, "r") as f:
vscode_settings = f.read()
textmate_rule_start_end = find_textmate_rule_string_position(vscode_settings, textmate_rule_name)
if textmate_rule_start_end:
start, end, indent = textmate_rule_start_end
textmate_rule_str = json.dumps(textmate_rule, indent=4)
textmate_rule_str = textmate_rule_str.replace("\n", "\n" + " " * indent)
vscode_settings = vscode_settings[:start] + textmate_rule_str + vscode_settings[end + 1 :]
with open(vscode_settings_path, "w") as f:
f.write(vscode_settings)
else:
print("Textmate rule not found")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Component Hinting Helper")
parser.add_argument("component_directory", type=Path)
parser.add_argument("--file-patterns", nargs="+", default=["**/*.html.jinja"])
# Custom Data Output
parser.add_argument("--custom-data-file", default="jinjax-components.html-data.json")
# VSCode settings
parser.add_argument("--add-vscode-settings", action="store_true")
parser.add_argument("--vscode-settings-path", default=".vscode/settings.json")
parser.add_argument("--token-color", default="#4EC9B0")
parser.add_argument("--textmate-rule-name", default="Custom JinjaX Components")
args = parser.parse_args()
main(args)