cordscript 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cordscript/__init__.py +6 -0
- cordscript/client.py +590 -0
- cordscript/core/__init__.py +9 -0
- cordscript/core/context.py +33 -0
- cordscript/core/runtime.py +55 -0
- cordscript/core/variables.py +16 -0
- cordscript/exceptions/__init__.py +3 -0
- cordscript/exceptions/errors.py +9 -0
- cordscript/functions/__init__.py +45 -0
- cordscript/functions/database/__init__.py +4 -0
- cordscript/functions/database/database.py +846 -0
- cordscript/functions/database/store.py +69 -0
- cordscript/functions/discord/__init__.py +15 -0
- cordscript/functions/discord/components.py +134 -0
- cordscript/functions/discord/componentsv2.py +92 -0
- cordscript/functions/discord/embed.py +63 -0
- cordscript/functions/discord/interaction.py +48 -0
- cordscript/functions/discord/logic.py +87 -0
- cordscript/functions/discord/message.py +51 -0
- cordscript/functions/discord/moderation.py +179 -0
- cordscript/functions/discord/status.py +56 -0
- cordscript/functions/users/__init__.py +3 -0
- cordscript/functions/users/user.py +103 -0
- cordscript/functions/utility/__init__.py +14 -0
- cordscript/functions/utility/cooldown.py +35 -0
- cordscript/functions/utility/http.py +73 -0
- cordscript/functions/utility/json.py +201 -0
- cordscript/functions/utility/math.py +102 -0
- cordscript/functions/utility/random.py +27 -0
- cordscript/functions/utility/strings.py +201 -0
- cordscript/functions/utility/time.py +41 -0
- cordscript/parser.py +190 -0
- cordscript/setup.py +38 -0
- cordscript-1.0.0.dist-info/METADATA +17 -0
- cordscript-1.0.0.dist-info/RECORD +37 -0
- cordscript-1.0.0.dist-info/WHEEL +5 -0
- cordscript-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import os
|
|
3
|
+
import threading
|
|
4
|
+
from tinydb import TinyDB, Query
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Database:
|
|
8
|
+
def __init__(self, path: str = "database/data.json"):
|
|
9
|
+
self.path = path
|
|
10
|
+
directory = os.path.dirname(path)
|
|
11
|
+
if directory:
|
|
12
|
+
os.makedirs(directory, exist_ok=True)
|
|
13
|
+
self._lock = threading.Lock()
|
|
14
|
+
self._db = TinyDB(path)
|
|
15
|
+
self._tables = {
|
|
16
|
+
"user": self._db.table("users"),
|
|
17
|
+
"channel": self._db.table("channels"),
|
|
18
|
+
"guild": self._db.table("guilds"),
|
|
19
|
+
}
|
|
20
|
+
self._q = Query()
|
|
21
|
+
|
|
22
|
+
def _table(self, scope: str):
|
|
23
|
+
table = self._tables.get(scope)
|
|
24
|
+
if table is None:
|
|
25
|
+
raise ValueError(f"Escopo de database inválido: {scope}")
|
|
26
|
+
return table
|
|
27
|
+
|
|
28
|
+
def get(self, scope: str, scope_id: str, key: str, default: str = "") -> str:
|
|
29
|
+
scope_id = str(scope_id)
|
|
30
|
+
table = self._table(scope)
|
|
31
|
+
with self._lock:
|
|
32
|
+
doc = table.get(self._q.id == scope_id)
|
|
33
|
+
if not doc:
|
|
34
|
+
return default
|
|
35
|
+
return str(doc.get("vars", {}).get(key, default))
|
|
36
|
+
|
|
37
|
+
def set(self, scope: str, scope_id: str, key: str, value: str) -> None:
|
|
38
|
+
scope_id = str(scope_id)
|
|
39
|
+
table = self._table(scope)
|
|
40
|
+
with self._lock:
|
|
41
|
+
doc = table.get(self._q.id == scope_id)
|
|
42
|
+
if doc:
|
|
43
|
+
variables = dict(doc.get("vars", {}))
|
|
44
|
+
variables[key] = value
|
|
45
|
+
table.update({"vars": variables}, self._q.id == scope_id)
|
|
46
|
+
else:
|
|
47
|
+
table.insert({"id": scope_id, "vars": {key: value}})
|
|
48
|
+
|
|
49
|
+
def all(self, scope: str, scope_id: str) -> dict:
|
|
50
|
+
scope_id = str(scope_id)
|
|
51
|
+
table = self._table(scope)
|
|
52
|
+
with self._lock:
|
|
53
|
+
doc = table.get(self._q.id == scope_id)
|
|
54
|
+
return dict(doc.get("vars", {})) if doc else {}
|
|
55
|
+
|
|
56
|
+
def get_all(self) -> dict:
|
|
57
|
+
result = {}
|
|
58
|
+
with self._lock:
|
|
59
|
+
for scope_name, table in self._tables.items():
|
|
60
|
+
result[scope_name] = {}
|
|
61
|
+
for doc in table.all():
|
|
62
|
+
scope_id = doc.get("id", "unknown")
|
|
63
|
+
result[scope_name][scope_id] = doc.get("vars", {})
|
|
64
|
+
return result
|
|
65
|
+
|
|
66
|
+
def wipe(self) -> None:
|
|
67
|
+
with self._lock:
|
|
68
|
+
for table in self._tables.values():
|
|
69
|
+
table.truncate()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from .message import handle_message
|
|
2
|
+
from .interaction import handle_interaction
|
|
3
|
+
from .embed import handle_embed
|
|
4
|
+
from .components import handle_components, _flush_row, _flush_select
|
|
5
|
+
from .componentsv2 import handle_componentsv2
|
|
6
|
+
from .logic import handle_logic
|
|
7
|
+
from .moderation import handle_moderation
|
|
8
|
+
from .status import handle_status
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"handle_message", "handle_interaction", "handle_embed",
|
|
12
|
+
"handle_components", "handle_componentsv2", "handle_logic",
|
|
13
|
+
"handle_moderation", "handle_status",
|
|
14
|
+
"_flush_row", "_flush_select",
|
|
15
|
+
]
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
_STYLE_MAP = {
|
|
4
|
+
"primary": 1,
|
|
5
|
+
"secondary": 2,
|
|
6
|
+
"success": 3,
|
|
7
|
+
"danger": 4,
|
|
8
|
+
"link": 5,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _target_list(parser) -> list:
|
|
13
|
+
"""Action rows go into the current CV2 container if we're inside one,
|
|
14
|
+
otherwise into the top-level (legacy) components list."""
|
|
15
|
+
if parser._cv2_stack:
|
|
16
|
+
return parser._cv2_target()
|
|
17
|
+
return parser._components
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
async def handle_components(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
21
|
+
try:
|
|
22
|
+
match fn:
|
|
23
|
+
case "addactionrow":
|
|
24
|
+
items = list(parser._pending_row or [])
|
|
25
|
+
if parser._pending_select:
|
|
26
|
+
items.append(parser._pending_select)
|
|
27
|
+
if items:
|
|
28
|
+
_target_list(parser).append({"type": 1, "components": items})
|
|
29
|
+
parser._pending_row = []
|
|
30
|
+
parser._pending_select = None
|
|
31
|
+
return ""
|
|
32
|
+
|
|
33
|
+
case "addbutton":
|
|
34
|
+
if parser._pending_row is None:
|
|
35
|
+
return "[Error in $addButton: must be inside $addActionRow]"
|
|
36
|
+
|
|
37
|
+
custom_id = args[0].strip() if len(args) > 0 else ""
|
|
38
|
+
label = args[1] if len(args) > 1 else ""
|
|
39
|
+
style_raw = args[2].strip().lower() if len(args) > 2 and args[2].strip() else "secondary"
|
|
40
|
+
emoji = args[3].strip() if len(args) > 3 and args[3].strip() else ""
|
|
41
|
+
disabled = (args[4].strip().lower() if len(args) > 4 else "") in ("true", "yes", "1")
|
|
42
|
+
url = args[5].strip() if len(args) > 5 and args[5].strip() else ""
|
|
43
|
+
|
|
44
|
+
if not custom_id and not url:
|
|
45
|
+
return "[Error in $addButton: custom_id or url required]"
|
|
46
|
+
|
|
47
|
+
data: dict = {
|
|
48
|
+
"type": 2,
|
|
49
|
+
"style": _STYLE_MAP.get(style_raw, 2),
|
|
50
|
+
"label": label,
|
|
51
|
+
"disabled": disabled,
|
|
52
|
+
}
|
|
53
|
+
if url:
|
|
54
|
+
data["url"] = url
|
|
55
|
+
data["style"] = 5
|
|
56
|
+
else:
|
|
57
|
+
data["custom_id"] = custom_id
|
|
58
|
+
if emoji:
|
|
59
|
+
data["emoji"] = {"name": emoji}
|
|
60
|
+
|
|
61
|
+
parser._pending_row.append(data)
|
|
62
|
+
if len(parser._pending_row) >= 5:
|
|
63
|
+
_target_list(parser).append({"type": 1, "components": parser._pending_row})
|
|
64
|
+
parser._pending_row = []
|
|
65
|
+
return ""
|
|
66
|
+
|
|
67
|
+
case "addselectmenu":
|
|
68
|
+
if parser._pending_row is None:
|
|
69
|
+
return "[Error in $addSelectMenu: must be inside $addActionRow]"
|
|
70
|
+
|
|
71
|
+
custom_id = args[0].strip() if len(args) > 0 else ""
|
|
72
|
+
placeholder = args[1] if len(args) > 1 else ""
|
|
73
|
+
try:
|
|
74
|
+
min_values = int(args[2].strip()) if len(args) > 2 and args[2].strip() else 1
|
|
75
|
+
except ValueError:
|
|
76
|
+
min_values = 1
|
|
77
|
+
try:
|
|
78
|
+
max_values = int(args[3].strip()) if len(args) > 3 and args[3].strip() else 1
|
|
79
|
+
except ValueError:
|
|
80
|
+
max_values = 1
|
|
81
|
+
disabled = (args[4].strip().lower() if len(args) > 4 else "") in ("true", "yes", "1")
|
|
82
|
+
|
|
83
|
+
if not custom_id:
|
|
84
|
+
return "[Error in $addSelectMenu: custom_id required]"
|
|
85
|
+
|
|
86
|
+
parser._pending_select = {
|
|
87
|
+
"type": 3,
|
|
88
|
+
"custom_id": custom_id,
|
|
89
|
+
"placeholder": placeholder,
|
|
90
|
+
"min_values": min_values,
|
|
91
|
+
"max_values": max_values,
|
|
92
|
+
"disabled": disabled,
|
|
93
|
+
"options": [],
|
|
94
|
+
}
|
|
95
|
+
return ""
|
|
96
|
+
|
|
97
|
+
case "addoption":
|
|
98
|
+
if parser._pending_select is None:
|
|
99
|
+
return "[Error in $addOption: no $addSelectMenu started]"
|
|
100
|
+
label = args[0] if len(args) > 0 else ""
|
|
101
|
+
value = args[1] if len(args) > 1 else label
|
|
102
|
+
description = args[2] if len(args) > 2 else ""
|
|
103
|
+
emoji = args[3].strip() if len(args) > 3 and args[3].strip() else ""
|
|
104
|
+
default = (args[4].strip().lower() if len(args) > 4 else "") in ("true", "yes", "1")
|
|
105
|
+
|
|
106
|
+
option: dict = {"label": label, "value": value, "default": default}
|
|
107
|
+
if description:
|
|
108
|
+
option["description"] = description
|
|
109
|
+
if emoji:
|
|
110
|
+
option["emoji"] = {"name": emoji}
|
|
111
|
+
parser._pending_select["options"].append(option)
|
|
112
|
+
return ""
|
|
113
|
+
|
|
114
|
+
case _:
|
|
115
|
+
return None
|
|
116
|
+
|
|
117
|
+
except Exception as e:
|
|
118
|
+
return f"[Unexpected error in ${fn}: {e}]"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _flush_row(parser) -> None:
|
|
122
|
+
"""Called at the end of evaluate() to catch a row left open without
|
|
123
|
+
an explicit $addActionRow close."""
|
|
124
|
+
if parser._pending_row:
|
|
125
|
+
_target_list(parser).append({"type": 1, "components": parser._pending_row})
|
|
126
|
+
parser._pending_row = []
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _flush_select(parser) -> None:
|
|
130
|
+
"""Called at the end of evaluate() to catch a select menu left open
|
|
131
|
+
without an explicit $addActionRow close."""
|
|
132
|
+
if parser._pending_select:
|
|
133
|
+
_target_list(parser).append({"type": 1, "components": [parser._pending_select]})
|
|
134
|
+
parser._pending_select = None
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
async def handle_componentsv2(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
5
|
+
try:
|
|
6
|
+
match fn:
|
|
7
|
+
case "addcontainer":
|
|
8
|
+
color = args[1] if len(args) > 1 else None
|
|
9
|
+
|
|
10
|
+
# If an $addActionRow was opened inside this container and never
|
|
11
|
+
# explicitly closed, flush it into the container now (it's still
|
|
12
|
+
# the current target) before we pop the container's children off
|
|
13
|
+
# the stack.
|
|
14
|
+
if parser._pending_row or parser._pending_select:
|
|
15
|
+
items = list(parser._pending_row or [])
|
|
16
|
+
if parser._pending_select:
|
|
17
|
+
items.append(parser._pending_select)
|
|
18
|
+
if items:
|
|
19
|
+
parser._cv2_target().append({"type": 1, "components": items})
|
|
20
|
+
parser._pending_row = []
|
|
21
|
+
parser._pending_select = None
|
|
22
|
+
|
|
23
|
+
# Pop the children collected while this container's content was
|
|
24
|
+
# being evaluated (pushed onto the stack in parser._eval).
|
|
25
|
+
children = parser._cv2_stack.pop() if parser._cv2_stack else []
|
|
26
|
+
|
|
27
|
+
container: dict = {"type": 17, "components": children}
|
|
28
|
+
if color:
|
|
29
|
+
try:
|
|
30
|
+
container["accent_color"] = parser._parse_color(color)
|
|
31
|
+
except Exception:
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
parser._cv2_target().append(container)
|
|
35
|
+
return ""
|
|
36
|
+
|
|
37
|
+
case "addtextdisplay":
|
|
38
|
+
title = args[0] if len(args) > 0 else ""
|
|
39
|
+
value = args[1] if len(args) > 1 else ""
|
|
40
|
+
if title and value:
|
|
41
|
+
content = f"**{title}**\n{value}"
|
|
42
|
+
else:
|
|
43
|
+
content = title or value
|
|
44
|
+
if not content:
|
|
45
|
+
return ""
|
|
46
|
+
|
|
47
|
+
parser._cv2_target().append({"type": 10, "content": content})
|
|
48
|
+
return ""
|
|
49
|
+
|
|
50
|
+
case "addseparator":
|
|
51
|
+
parser._cv2_target().append({"type": 14, "divider": True, "spacing": 1})
|
|
52
|
+
return ""
|
|
53
|
+
|
|
54
|
+
case "addthumbnail":
|
|
55
|
+
url = args[0] if len(args) > 0 else ""
|
|
56
|
+
if not url:
|
|
57
|
+
return ""
|
|
58
|
+
|
|
59
|
+
target = parser._cv2_target()
|
|
60
|
+
# If the previous item is a section without an accessory yet,
|
|
61
|
+
# attach the thumbnail there instead of adding a stray component.
|
|
62
|
+
if target and target[-1].get("type") == 9 and "accessory" not in target[-1]:
|
|
63
|
+
target[-1]["accessory"] = {"type": 11, "media": {"url": url}}
|
|
64
|
+
else:
|
|
65
|
+
target.append({"type": 11, "media": {"url": url}})
|
|
66
|
+
return ""
|
|
67
|
+
|
|
68
|
+
case "addmediagallery":
|
|
69
|
+
urls = args[0] if len(args) > 0 else ""
|
|
70
|
+
items = [{"media": {"url": u.strip()}} for u in urls.split(";") if u.strip()]
|
|
71
|
+
if not items:
|
|
72
|
+
return ""
|
|
73
|
+
|
|
74
|
+
parser._cv2_target().append({"type": 12, "items": items})
|
|
75
|
+
return ""
|
|
76
|
+
|
|
77
|
+
case "addsection":
|
|
78
|
+
title = args[0] if len(args) > 0 else ""
|
|
79
|
+
if not title:
|
|
80
|
+
return ""
|
|
81
|
+
|
|
82
|
+
parser._cv2_target().append({
|
|
83
|
+
"type": 9,
|
|
84
|
+
"components": [{"type": 10, "content": title}],
|
|
85
|
+
})
|
|
86
|
+
return ""
|
|
87
|
+
|
|
88
|
+
case _:
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
except Exception as e:
|
|
92
|
+
return f"[Unexpected error in ${fn}: {e}]"
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from datetime import datetime, timezone
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
async def handle_embed(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
6
|
+
try:
|
|
7
|
+
match fn:
|
|
8
|
+
case "title":
|
|
9
|
+
parser._current_embed()._title = args[0] if args else raw
|
|
10
|
+
return ""
|
|
11
|
+
|
|
12
|
+
case "description":
|
|
13
|
+
parser._current_embed()._description = args[0] if args else raw
|
|
14
|
+
return ""
|
|
15
|
+
|
|
16
|
+
case "color" | "colour":
|
|
17
|
+
raw_color = args[0] if args else raw
|
|
18
|
+
parser._current_embed()._color = parser._parse_color(raw_color)
|
|
19
|
+
return ""
|
|
20
|
+
|
|
21
|
+
case "footer":
|
|
22
|
+
parser._current_embed()._footer_text = args[0] if args else raw
|
|
23
|
+
return ""
|
|
24
|
+
|
|
25
|
+
case "footericon":
|
|
26
|
+
parser._current_embed()._footer_icon = args[0] if args else raw
|
|
27
|
+
return ""
|
|
28
|
+
|
|
29
|
+
case "image":
|
|
30
|
+
parser._current_embed()._image = args[0] if args else raw
|
|
31
|
+
return ""
|
|
32
|
+
|
|
33
|
+
case "thumbnail":
|
|
34
|
+
parser._current_embed()._thumbnail = args[0] if args else raw
|
|
35
|
+
return ""
|
|
36
|
+
|
|
37
|
+
case "author":
|
|
38
|
+
eb = parser._current_embed()
|
|
39
|
+
eb._author_text = args[0] if len(args) > 0 else ""
|
|
40
|
+
eb._author_icon = args[1] if len(args) > 1 else None
|
|
41
|
+
return ""
|
|
42
|
+
|
|
43
|
+
case "addfield":
|
|
44
|
+
name = args[0] if len(args) > 0 else "\u200b"
|
|
45
|
+
value = args[1] if len(args) > 1 else "\u200b"
|
|
46
|
+
inline_raw = args[2].strip().lower() if len(args) > 2 else "false"
|
|
47
|
+
inline = inline_raw in ("true", "1", "yes")
|
|
48
|
+
parser._current_embed()._fields.append({
|
|
49
|
+
"name": name,
|
|
50
|
+
"value": value,
|
|
51
|
+
"inline": inline,
|
|
52
|
+
})
|
|
53
|
+
return ""
|
|
54
|
+
|
|
55
|
+
case "addtimestamp":
|
|
56
|
+
parser._current_embed()._timestamp = True
|
|
57
|
+
return ""
|
|
58
|
+
|
|
59
|
+
case _:
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
except Exception as e:
|
|
63
|
+
return f"[Unexpected error in ${fn}: {e}]"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import discord
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
async def handle_interaction(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
6
|
+
ctx = parser.ctx
|
|
7
|
+
is_interaction = isinstance(ctx, discord.Interaction)
|
|
8
|
+
|
|
9
|
+
match fn:
|
|
10
|
+
case "customid":
|
|
11
|
+
if is_interaction and ctx.data:
|
|
12
|
+
return ctx.data.get("custom_id", "")
|
|
13
|
+
return ""
|
|
14
|
+
|
|
15
|
+
case "defer":
|
|
16
|
+
if is_interaction and not ctx.response.is_done():
|
|
17
|
+
await ctx.response.defer()
|
|
18
|
+
return ""
|
|
19
|
+
|
|
20
|
+
case "deferephemeral":
|
|
21
|
+
if is_interaction and not ctx.response.is_done():
|
|
22
|
+
await ctx.response.defer(ephemeral=True)
|
|
23
|
+
return ""
|
|
24
|
+
|
|
25
|
+
case "interactionupdate":
|
|
26
|
+
content = args[0] if args else raw
|
|
27
|
+
if is_interaction and not ctx.response.is_done():
|
|
28
|
+
await ctx.response.edit_message(content=content)
|
|
29
|
+
elif is_interaction:
|
|
30
|
+
await ctx.edit_original_response(content=content)
|
|
31
|
+
return ""
|
|
32
|
+
|
|
33
|
+
case "ephemeral":
|
|
34
|
+
parser._ephemeral = True
|
|
35
|
+
return ""
|
|
36
|
+
|
|
37
|
+
case "interactionuser":
|
|
38
|
+
if is_interaction:
|
|
39
|
+
return str(ctx.user.id)
|
|
40
|
+
return str(ctx.author.id)
|
|
41
|
+
|
|
42
|
+
case "interactionchannel":
|
|
43
|
+
if is_interaction:
|
|
44
|
+
return str(ctx.channel_id)
|
|
45
|
+
return str(ctx.channel.id)
|
|
46
|
+
|
|
47
|
+
case _:
|
|
48
|
+
return None
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from ...exceptions import StopExecution
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def _evaluate_condition(condition: str) -> bool:
|
|
6
|
+
condition = condition.strip()
|
|
7
|
+
for op in (">=", "<=", "!=", "==", ">", "<"):
|
|
8
|
+
if op in condition:
|
|
9
|
+
left, right = condition.split(op, 1)
|
|
10
|
+
left, right = left.strip(), right.strip()
|
|
11
|
+
try:
|
|
12
|
+
l_val: float | str = float(left)
|
|
13
|
+
r_val: float | str = float(right)
|
|
14
|
+
except ValueError:
|
|
15
|
+
l_val, r_val = left, right
|
|
16
|
+
match op:
|
|
17
|
+
case "==": return l_val == r_val
|
|
18
|
+
case "!=": return l_val != r_val
|
|
19
|
+
case ">": return l_val > r_val
|
|
20
|
+
case "<": return l_val < r_val
|
|
21
|
+
case ">=": return l_val >= r_val
|
|
22
|
+
case "<=": return l_val <= r_val
|
|
23
|
+
return bool(condition) and condition.lower() not in ("false", "0", "no")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
async def handle_logic(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
27
|
+
try:
|
|
28
|
+
match fn:
|
|
29
|
+
case "if":
|
|
30
|
+
if not args:
|
|
31
|
+
return f"[Error in $if: condition required]"
|
|
32
|
+
condition = args[0].strip()
|
|
33
|
+
true_val = args[1] if len(args) > 1 else ""
|
|
34
|
+
false_val = args[2] if len(args) > 2 else ""
|
|
35
|
+
return true_val if _evaluate_condition(condition) else false_val
|
|
36
|
+
|
|
37
|
+
case "and":
|
|
38
|
+
if not args:
|
|
39
|
+
return f"[Error in $and: at least one condition required]"
|
|
40
|
+
return "true" if all(_evaluate_condition(a.strip()) for a in args) else "false"
|
|
41
|
+
|
|
42
|
+
case "or":
|
|
43
|
+
if not args:
|
|
44
|
+
return f"[Error in $or: at least one condition required]"
|
|
45
|
+
return "true" if any(_evaluate_condition(a.strip()) for a in args) else "false"
|
|
46
|
+
|
|
47
|
+
case "not":
|
|
48
|
+
val = args[0].strip() if args else ""
|
|
49
|
+
return "false" if _evaluate_condition(val) else "true"
|
|
50
|
+
|
|
51
|
+
case "switch":
|
|
52
|
+
if not args:
|
|
53
|
+
return f"[Error in $switch: value required]"
|
|
54
|
+
value = args[0].strip()
|
|
55
|
+
i = 1
|
|
56
|
+
while i + 1 < len(args):
|
|
57
|
+
if value == args[i].strip():
|
|
58
|
+
return args[i + 1]
|
|
59
|
+
i += 2
|
|
60
|
+
return args[i] if i < len(args) else ""
|
|
61
|
+
|
|
62
|
+
case "onlyif":
|
|
63
|
+
if not args:
|
|
64
|
+
return "[Error in $onlyIf: condition required]"
|
|
65
|
+
condition = args[0].strip()
|
|
66
|
+
error_msg = args[1] if len(args) > 1 else ""
|
|
67
|
+
if not _evaluate_condition(condition):
|
|
68
|
+
raise StopExecution(error_msg)
|
|
69
|
+
return ""
|
|
70
|
+
|
|
71
|
+
case "try":
|
|
72
|
+
code = args[0] if len(args) > 0 else ""
|
|
73
|
+
fallback = args[1] if len(args) > 1 else ""
|
|
74
|
+
try:
|
|
75
|
+
return await parser._eval(code)
|
|
76
|
+
except StopExecution:
|
|
77
|
+
raise
|
|
78
|
+
except Exception:
|
|
79
|
+
return fallback
|
|
80
|
+
|
|
81
|
+
case _:
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
except StopExecution:
|
|
85
|
+
raise
|
|
86
|
+
except Exception as e:
|
|
87
|
+
return f"[Unexpected error in ${fn}: {e}]"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
async def handle_message(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
5
|
+
try:
|
|
6
|
+
match fn:
|
|
7
|
+
case "reply":
|
|
8
|
+
parser._reply = True
|
|
9
|
+
content = args[0] if args else (raw if raw else None)
|
|
10
|
+
if content:
|
|
11
|
+
parser._reply_content = content
|
|
12
|
+
return ""
|
|
13
|
+
|
|
14
|
+
case "deleteafter":
|
|
15
|
+
seconds = args[0].strip() if args else raw.strip()
|
|
16
|
+
try:
|
|
17
|
+
parser._delete_after = float(seconds)
|
|
18
|
+
except ValueError:
|
|
19
|
+
return "[Error in $deleteAfter: invalid duration]"
|
|
20
|
+
return ""
|
|
21
|
+
|
|
22
|
+
case "sendmessage":
|
|
23
|
+
channel_id = args[0].strip() if len(args) > 0 else ""
|
|
24
|
+
content = args[1] if len(args) > 1 else ""
|
|
25
|
+
return_var = args[2].strip() if len(args) > 2 and args[2].strip() else None
|
|
26
|
+
if not channel_id:
|
|
27
|
+
return "[Error in $sendMessage: channel id required]"
|
|
28
|
+
try:
|
|
29
|
+
cid = int(channel_id)
|
|
30
|
+
except ValueError:
|
|
31
|
+
return "[Error in $sendMessage: invalid channel id]"
|
|
32
|
+
msg = {
|
|
33
|
+
"channel_id": cid,
|
|
34
|
+
"content": content,
|
|
35
|
+
"embeds": [],
|
|
36
|
+
"components": [],
|
|
37
|
+
"cv2": [],
|
|
38
|
+
"delete_after": None,
|
|
39
|
+
}
|
|
40
|
+
if return_var:
|
|
41
|
+
msg["return_id"] = True
|
|
42
|
+
msg["return_var"] = return_var
|
|
43
|
+
msg["_parser"] = parser
|
|
44
|
+
parser._extra_messages.append(msg)
|
|
45
|
+
return ""
|
|
46
|
+
|
|
47
|
+
case _:
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
except Exception as e:
|
|
51
|
+
return f"[Unexpected error in ${fn}: {e}]"
|