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,102 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import ast
|
|
3
|
+
import operator
|
|
4
|
+
|
|
5
|
+
_OPERATORS = {
|
|
6
|
+
ast.Add: operator.add,
|
|
7
|
+
ast.Sub: operator.sub,
|
|
8
|
+
ast.Mult: operator.mul,
|
|
9
|
+
ast.Div: operator.truediv,
|
|
10
|
+
ast.FloorDiv: operator.floordiv,
|
|
11
|
+
ast.Mod: operator.mod,
|
|
12
|
+
ast.Pow: operator.pow,
|
|
13
|
+
ast.USub: operator.neg,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _eval_expr(node):
|
|
18
|
+
if isinstance(node, ast.Expression):
|
|
19
|
+
return _eval_expr(node.body)
|
|
20
|
+
elif isinstance(node, ast.Constant):
|
|
21
|
+
return node.value
|
|
22
|
+
elif isinstance(node, ast.BinOp):
|
|
23
|
+
op = _OPERATORS.get(type(node.op))
|
|
24
|
+
if op is None:
|
|
25
|
+
raise ValueError(f"Unsupported operator: {type(node.op).__name__}")
|
|
26
|
+
return op(_eval_expr(node.left), _eval_expr(node.right))
|
|
27
|
+
elif isinstance(node, ast.UnaryOp):
|
|
28
|
+
op = _OPERATORS.get(type(node.op))
|
|
29
|
+
if op is None:
|
|
30
|
+
raise ValueError(f"Unsupported operator: {type(node.op).__name__}")
|
|
31
|
+
return op(_eval_expr(node.operand))
|
|
32
|
+
raise ValueError(f"Unsupported expression: {type(node).__name__}")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def safe_math(expr: str) -> str:
|
|
36
|
+
tree = ast.parse(expr.strip(), mode="eval")
|
|
37
|
+
result = _eval_expr(tree)
|
|
38
|
+
if isinstance(result, float) and result.is_integer():
|
|
39
|
+
return str(int(result))
|
|
40
|
+
return str(result)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
async def handle_math(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
44
|
+
try:
|
|
45
|
+
match fn:
|
|
46
|
+
case "math":
|
|
47
|
+
expr = args[0] if args else raw
|
|
48
|
+
try:
|
|
49
|
+
return safe_math(expr)
|
|
50
|
+
except Exception as e:
|
|
51
|
+
return f"[Error in $math: {e}]"
|
|
52
|
+
|
|
53
|
+
case "round":
|
|
54
|
+
try:
|
|
55
|
+
num = float(args[0].strip()) if args else 0
|
|
56
|
+
places = int(args[1].strip()) if len(args) > 1 and args[1].strip() else 0
|
|
57
|
+
r = round(num, places)
|
|
58
|
+
return str(r if places > 0 else int(r))
|
|
59
|
+
except ValueError as e:
|
|
60
|
+
return f"[Error in $round: {e}]"
|
|
61
|
+
|
|
62
|
+
case "abs":
|
|
63
|
+
try:
|
|
64
|
+
val = float(args[0].strip()) if args else 0
|
|
65
|
+
r = abs(val)
|
|
66
|
+
return str(int(r) if r == int(r) else r)
|
|
67
|
+
except ValueError as e:
|
|
68
|
+
return f"[Error in $abs: {e}]"
|
|
69
|
+
|
|
70
|
+
case "max":
|
|
71
|
+
try:
|
|
72
|
+
vals = [float(a.strip()) for a in args if a.strip()]
|
|
73
|
+
if not vals:
|
|
74
|
+
return f"[Error in $max: no values provided]"
|
|
75
|
+
r = max(vals)
|
|
76
|
+
return str(int(r) if r == int(r) else r)
|
|
77
|
+
except ValueError as e:
|
|
78
|
+
return f"[Error in $max: {e}]"
|
|
79
|
+
|
|
80
|
+
case "min":
|
|
81
|
+
try:
|
|
82
|
+
vals = [float(a.strip()) for a in args if a.strip()]
|
|
83
|
+
if not vals:
|
|
84
|
+
return f"[Error in $min: no values provided]"
|
|
85
|
+
r = min(vals)
|
|
86
|
+
return str(int(r) if r == int(r) else r)
|
|
87
|
+
except ValueError as e:
|
|
88
|
+
return f"[Error in $min: {e}]"
|
|
89
|
+
|
|
90
|
+
case "isnumber":
|
|
91
|
+
val = args[0].strip() if args else ""
|
|
92
|
+
try:
|
|
93
|
+
float(val)
|
|
94
|
+
return "true"
|
|
95
|
+
except ValueError:
|
|
96
|
+
return "false"
|
|
97
|
+
|
|
98
|
+
case _:
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
except Exception as e:
|
|
102
|
+
return f"[Unexpected error in ${fn}: {e}]"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import random as _random
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
async def handle_random(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
6
|
+
try:
|
|
7
|
+
match fn:
|
|
8
|
+
case "random":
|
|
9
|
+
try:
|
|
10
|
+
min_val = int(args[0].strip()) if len(args) > 0 and args[0].strip() else 1
|
|
11
|
+
max_val = int(args[1].strip()) if len(args) > 1 and args[1].strip() else 100
|
|
12
|
+
if min_val > max_val:
|
|
13
|
+
min_val, max_val = max_val, min_val
|
|
14
|
+
return str(_random.randint(min_val, max_val))
|
|
15
|
+
except ValueError as e:
|
|
16
|
+
return f"[Error in $random: {e}]"
|
|
17
|
+
|
|
18
|
+
case "randomitem":
|
|
19
|
+
if not args:
|
|
20
|
+
return ""
|
|
21
|
+
return _random.choice(args)
|
|
22
|
+
|
|
23
|
+
case _:
|
|
24
|
+
return None
|
|
25
|
+
|
|
26
|
+
except Exception as e:
|
|
27
|
+
return f"[Unexpected error in ${fn}: {e}]"
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from ...exceptions import StopExecution
|
|
3
|
+
from ...core.context import get_author_id
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _get_args(parser) -> list[str]:
|
|
7
|
+
if not hasattr(parser.ctx, "content"):
|
|
8
|
+
return []
|
|
9
|
+
parts = parser.ctx.content.split(None, 1)
|
|
10
|
+
if len(parts) < 2:
|
|
11
|
+
return []
|
|
12
|
+
return parts[1].split()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def handle_strings(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
16
|
+
try:
|
|
17
|
+
match fn:
|
|
18
|
+
case "upper":
|
|
19
|
+
return (args[0] if args else raw).upper()
|
|
20
|
+
|
|
21
|
+
case "lower":
|
|
22
|
+
return (args[0] if args else raw).lower()
|
|
23
|
+
|
|
24
|
+
case "length":
|
|
25
|
+
return str(len(args[0] if args else raw))
|
|
26
|
+
|
|
27
|
+
case "trim":
|
|
28
|
+
return (args[0] if args else raw).strip()
|
|
29
|
+
|
|
30
|
+
case "replace":
|
|
31
|
+
if len(args) < 3:
|
|
32
|
+
return f"[Error in $replace: expected 3 arguments (text;from;to)]"
|
|
33
|
+
return args[0].replace(args[1], args[2])
|
|
34
|
+
|
|
35
|
+
case "includes":
|
|
36
|
+
if len(args) < 2:
|
|
37
|
+
return f"[Error in $includes: expected 2 arguments]"
|
|
38
|
+
return "true" if args[1] in args[0] else "false"
|
|
39
|
+
|
|
40
|
+
case "startswith":
|
|
41
|
+
if len(args) < 2:
|
|
42
|
+
return f"[Error in $startsWith: expected 2 arguments]"
|
|
43
|
+
return "true" if args[0].startswith(args[1]) else "false"
|
|
44
|
+
|
|
45
|
+
case "endswith":
|
|
46
|
+
if len(args) < 2:
|
|
47
|
+
return f"[Error in $endsWith: expected 2 arguments]"
|
|
48
|
+
return "true" if args[0].endswith(args[1]) else "false"
|
|
49
|
+
|
|
50
|
+
case "indexof":
|
|
51
|
+
if len(args) < 2:
|
|
52
|
+
return f"[Error in $indexOf: expected 2 arguments]"
|
|
53
|
+
return str(args[0].find(args[1]))
|
|
54
|
+
|
|
55
|
+
case "slice":
|
|
56
|
+
if not args:
|
|
57
|
+
return f"[Error in $slice: expected at least 1 argument]"
|
|
58
|
+
text = args[0]
|
|
59
|
+
try:
|
|
60
|
+
start = int(args[1].strip()) if len(args) > 1 else 0
|
|
61
|
+
end = int(args[2].strip()) if len(args) > 2 else len(text)
|
|
62
|
+
return text[start:end]
|
|
63
|
+
except (ValueError, IndexError) as e:
|
|
64
|
+
return f"[Error in $slice: {e}]"
|
|
65
|
+
|
|
66
|
+
case "concat":
|
|
67
|
+
return "".join(args)
|
|
68
|
+
|
|
69
|
+
case "split":
|
|
70
|
+
if not args:
|
|
71
|
+
return f"[Error in $split: expected at least 1 argument]"
|
|
72
|
+
text = args[0]
|
|
73
|
+
sep = args[1] if len(args) > 1 else ","
|
|
74
|
+
try:
|
|
75
|
+
index = int(args[2].strip()) - 1 if len(args) > 2 and args[2].strip() else None
|
|
76
|
+
except ValueError as e:
|
|
77
|
+
return f"[Error in $split: {e}]"
|
|
78
|
+
parts = text.split(sep)
|
|
79
|
+
if index is not None:
|
|
80
|
+
return parts[index] if 0 <= index < len(parts) else ""
|
|
81
|
+
return sep.join(parts)
|
|
82
|
+
|
|
83
|
+
case "repeat":
|
|
84
|
+
try:
|
|
85
|
+
times = max(0, int(args[0].strip())) if args and args[0].strip() else 1
|
|
86
|
+
except ValueError as e:
|
|
87
|
+
return f"[Error in $repeat: {e}]"
|
|
88
|
+
text = args[1] if len(args) > 1 else ""
|
|
89
|
+
return text * times
|
|
90
|
+
|
|
91
|
+
case "let":
|
|
92
|
+
name = args[0].strip() if args else ""
|
|
93
|
+
if not name:
|
|
94
|
+
return f"[Error in $let: variable name required]"
|
|
95
|
+
parser._vars[name] = args[1] if len(args) > 1 else ""
|
|
96
|
+
return ""
|
|
97
|
+
|
|
98
|
+
case "get":
|
|
99
|
+
name = args[0].strip() if args else ""
|
|
100
|
+
if not name:
|
|
101
|
+
return f"[Error in $get: variable name required]"
|
|
102
|
+
return parser._vars.get(name, "")
|
|
103
|
+
|
|
104
|
+
case "textsplit":
|
|
105
|
+
text = args[0] if len(args) > 0 else ""
|
|
106
|
+
sep = args[1] if len(args) > 1 else ","
|
|
107
|
+
parser._split_cache = text.split(sep)
|
|
108
|
+
return ""
|
|
109
|
+
|
|
110
|
+
case "splittext":
|
|
111
|
+
cache = parser._split_cache
|
|
112
|
+
if not cache:
|
|
113
|
+
return ""
|
|
114
|
+
try:
|
|
115
|
+
index = int(args[0].strip()) - 1 if args and args[0].strip() else 0
|
|
116
|
+
return cache[index] if 0 <= index < len(cache) else ""
|
|
117
|
+
except (ValueError, IndexError) as e:
|
|
118
|
+
return f"[Error in $splitText: {e}]"
|
|
119
|
+
|
|
120
|
+
case "args":
|
|
121
|
+
return " ".join(_get_args(parser))
|
|
122
|
+
|
|
123
|
+
case "arg":
|
|
124
|
+
try:
|
|
125
|
+
index = int(args[0].strip()) - 1 if args and args[0].strip() else 0
|
|
126
|
+
parts = _get_args(parser)
|
|
127
|
+
return parts[index] if 0 <= index < len(parts) else ""
|
|
128
|
+
except (ValueError, IndexError):
|
|
129
|
+
return ""
|
|
130
|
+
|
|
131
|
+
case "argslength":
|
|
132
|
+
return str(len(_get_args(parser)))
|
|
133
|
+
|
|
134
|
+
case "channelid":
|
|
135
|
+
if hasattr(parser.ctx, "channel") and parser.ctx.channel:
|
|
136
|
+
return str(parser.ctx.channel.id)
|
|
137
|
+
if hasattr(parser.ctx, "channel_id") and parser.ctx.channel_id:
|
|
138
|
+
return str(parser.ctx.channel_id)
|
|
139
|
+
return ""
|
|
140
|
+
|
|
141
|
+
case "channelname":
|
|
142
|
+
if hasattr(parser.ctx, "channel") and parser.ctx.channel:
|
|
143
|
+
return str(parser.ctx.channel.name)
|
|
144
|
+
return ""
|
|
145
|
+
|
|
146
|
+
case "messageid":
|
|
147
|
+
return str(parser.ctx.id) if hasattr(parser.ctx, "id") else ""
|
|
148
|
+
|
|
149
|
+
case "stop":
|
|
150
|
+
raise StopExecution()
|
|
151
|
+
|
|
152
|
+
case "eval":
|
|
153
|
+
expr = args[0] if args else raw
|
|
154
|
+
if "$" in expr:
|
|
155
|
+
return await parser._eval(expr)
|
|
156
|
+
from .math import safe_math
|
|
157
|
+
try:
|
|
158
|
+
return safe_math(expr)
|
|
159
|
+
except Exception:
|
|
160
|
+
return expr
|
|
161
|
+
|
|
162
|
+
case "dpyeval":
|
|
163
|
+
code = args[0] if args else raw
|
|
164
|
+
try:
|
|
165
|
+
ctx = parser.ctx
|
|
166
|
+
local_vars = {
|
|
167
|
+
"ctx": ctx,
|
|
168
|
+
"bot": parser.client,
|
|
169
|
+
"client": parser.client,
|
|
170
|
+
"channel": getattr(ctx, "channel", None),
|
|
171
|
+
"guild": getattr(ctx, "guild", None),
|
|
172
|
+
"author": getattr(ctx, "author", getattr(ctx, "user", None)),
|
|
173
|
+
}
|
|
174
|
+
wrapped = "async def __fn():\n" + "\n".join(f" {line}" for line in code.splitlines())
|
|
175
|
+
exec(wrapped, local_vars)
|
|
176
|
+
ret = await local_vars["__fn"]()
|
|
177
|
+
return str(ret) if ret is not None else ""
|
|
178
|
+
except Exception as e:
|
|
179
|
+
return f"[Error in $dpyEval: {e}]"
|
|
180
|
+
|
|
181
|
+
case "message":
|
|
182
|
+
if not hasattr(parser.ctx, "content"):
|
|
183
|
+
return ""
|
|
184
|
+
parts = parser.ctx.content.split(None, 1)
|
|
185
|
+
content = parts[1] if len(parts) > 1 else ""
|
|
186
|
+
if not args or not args[0].strip():
|
|
187
|
+
return content
|
|
188
|
+
try:
|
|
189
|
+
index = int(args[0].strip()) - 1
|
|
190
|
+
words = content.split()
|
|
191
|
+
return words[index] if 0 <= index < len(words) else ""
|
|
192
|
+
except (ValueError, IndexError) as e:
|
|
193
|
+
return f"[Error in $message: {e}]"
|
|
194
|
+
|
|
195
|
+
case _:
|
|
196
|
+
return None
|
|
197
|
+
|
|
198
|
+
except StopExecution:
|
|
199
|
+
raise
|
|
200
|
+
except Exception as e:
|
|
201
|
+
return f"[Unexpected error in ${fn}: {e}]"
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import time as time_module
|
|
3
|
+
from datetime import datetime, timezone
|
|
4
|
+
|
|
5
|
+
_BOT_START_TIME = time_module.monotonic()
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def handle_time(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
9
|
+
try:
|
|
10
|
+
match fn:
|
|
11
|
+
case "ping":
|
|
12
|
+
return str(round(parser.client.latency * 1000))
|
|
13
|
+
|
|
14
|
+
case "executiontime":
|
|
15
|
+
return str(round((time_module.monotonic() - parser._start_time) * 1000))
|
|
16
|
+
|
|
17
|
+
case "uptime":
|
|
18
|
+
elapsed = int(time_module.monotonic() - _BOT_START_TIME)
|
|
19
|
+
fmt = args[0].strip().lower() if args and args[0].strip() else "time"
|
|
20
|
+
if fmt == "timestamp":
|
|
21
|
+
start_unix = int(datetime.now(timezone.utc).timestamp()) - elapsed
|
|
22
|
+
return str(start_unix)
|
|
23
|
+
h = elapsed // 3600
|
|
24
|
+
m = (elapsed % 3600) // 60
|
|
25
|
+
s = elapsed % 60
|
|
26
|
+
return f"{h:02d}:{m:02d}:{s:02d}"
|
|
27
|
+
|
|
28
|
+
case "gettimestamp":
|
|
29
|
+
return str(int(datetime.now(timezone.utc).timestamp()))
|
|
30
|
+
|
|
31
|
+
case "time":
|
|
32
|
+
return datetime.now().strftime("%H:%M:%S")
|
|
33
|
+
|
|
34
|
+
case "date":
|
|
35
|
+
return datetime.now().strftime("%d/%m/%Y")
|
|
36
|
+
|
|
37
|
+
case _:
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
except Exception as e:
|
|
41
|
+
return f"[Unexpected error in ${fn}: {e}]"
|
cordscript/parser.py
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import time
|
|
3
|
+
from datetime import datetime, timezone
|
|
4
|
+
from .exceptions import StopExecution, CooldownError
|
|
5
|
+
from .core import find_functions, split_args
|
|
6
|
+
from .functions import (
|
|
7
|
+
handle_message, handle_interaction, handle_embed,
|
|
8
|
+
handle_components, handle_componentsv2, handle_logic,
|
|
9
|
+
handle_user, handle_database, handle_moderation, handle_status,
|
|
10
|
+
handle_math, handle_time, handle_random,
|
|
11
|
+
handle_http, handle_cooldown, handle_json, handle_strings,
|
|
12
|
+
_flush_select, _flush_row,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class EmbedBuilder:
|
|
17
|
+
def __init__(self):
|
|
18
|
+
self.reset()
|
|
19
|
+
|
|
20
|
+
def reset(self):
|
|
21
|
+
self._title: str | None = None
|
|
22
|
+
self._description: str | None = None
|
|
23
|
+
self._color: int | None = None
|
|
24
|
+
self._footer_text: str | None = None
|
|
25
|
+
self._footer_icon: str | None = None
|
|
26
|
+
self._image: str | None = None
|
|
27
|
+
self._thumbnail: str | None = None
|
|
28
|
+
self._author_text: str | None = None
|
|
29
|
+
self._author_icon: str | None = None
|
|
30
|
+
self._fields: list[dict] = []
|
|
31
|
+
self._timestamp: bool = False
|
|
32
|
+
|
|
33
|
+
def has_data(self) -> bool:
|
|
34
|
+
return any([
|
|
35
|
+
self._title, self._description, self._color is not None,
|
|
36
|
+
self._footer_text, self._image, self._thumbnail,
|
|
37
|
+
self._author_text, self._fields, self._timestamp,
|
|
38
|
+
])
|
|
39
|
+
|
|
40
|
+
def to_dict(self) -> dict:
|
|
41
|
+
embed: dict = {"type": "rich"}
|
|
42
|
+
if self._title:
|
|
43
|
+
embed["title"] = self._title
|
|
44
|
+
if self._description:
|
|
45
|
+
embed["description"] = self._description
|
|
46
|
+
if self._color is not None:
|
|
47
|
+
embed["color"] = self._color
|
|
48
|
+
if self._footer_text:
|
|
49
|
+
embed["footer"] = {"text": self._footer_text}
|
|
50
|
+
if self._footer_icon:
|
|
51
|
+
embed["footer"]["icon_url"] = self._footer_icon
|
|
52
|
+
if self._image:
|
|
53
|
+
embed["image"] = {"url": self._image}
|
|
54
|
+
if self._thumbnail:
|
|
55
|
+
embed["thumbnail"] = {"url": self._thumbnail}
|
|
56
|
+
if self._author_text:
|
|
57
|
+
embed["author"] = {"name": self._author_text}
|
|
58
|
+
if self._author_icon:
|
|
59
|
+
embed["author"]["icon_url"] = self._author_icon
|
|
60
|
+
if self._fields:
|
|
61
|
+
embed["fields"] = self._fields
|
|
62
|
+
if self._timestamp:
|
|
63
|
+
embed["timestamp"] = datetime.now(timezone.utc).isoformat()
|
|
64
|
+
return embed
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class Parser:
|
|
68
|
+
def __init__(self, ctx, client):
|
|
69
|
+
self.ctx = ctx
|
|
70
|
+
self.client = client
|
|
71
|
+
self._start_time = time.monotonic()
|
|
72
|
+
self._embeds: list[EmbedBuilder] = [EmbedBuilder()]
|
|
73
|
+
self._extra_messages: list[dict] = []
|
|
74
|
+
self._reply: bool = False
|
|
75
|
+
self._reply_content: str | None = None
|
|
76
|
+
self._delete_after: float | None = None
|
|
77
|
+
self._components: list[dict] = []
|
|
78
|
+
self._cv2_pending: list = []
|
|
79
|
+
self._cv2_stack: list[list] = []
|
|
80
|
+
self._cv2_in_container: bool = False
|
|
81
|
+
self._split_cache: list[str] = []
|
|
82
|
+
self._ephemeral: bool = False
|
|
83
|
+
self._vars: dict[str, str] = {}
|
|
84
|
+
self._pending_select: dict | None = None
|
|
85
|
+
self._pending_row: list | None = None
|
|
86
|
+
self._stopped: bool = False
|
|
87
|
+
self._cooldown_msg: str | None = None
|
|
88
|
+
|
|
89
|
+
def _current_embed(self) -> EmbedBuilder:
|
|
90
|
+
return self._embeds[-1]
|
|
91
|
+
|
|
92
|
+
def _cv2_target(self) -> list:
|
|
93
|
+
return self._cv2_stack[-1] if self._cv2_stack else self._cv2_pending
|
|
94
|
+
|
|
95
|
+
def _parse_color(self, value: str) -> int:
|
|
96
|
+
value = value.strip().lstrip("#")
|
|
97
|
+
try:
|
|
98
|
+
return int(value, 16)
|
|
99
|
+
except ValueError:
|
|
100
|
+
named = {
|
|
101
|
+
"red": 0xFF0000, "green": 0x00FF00, "blue": 0x0000FF,
|
|
102
|
+
"yellow": 0xFFFF00, "orange": 0xFF8000, "purple": 0x800080,
|
|
103
|
+
"pink": 0xFFC0CB, "white": 0xFFFFFF, "black": 0x000000,
|
|
104
|
+
"cyan": 0x00FFFF, "blurple": 0x5865F2, "gray": 0x808080,
|
|
105
|
+
}
|
|
106
|
+
return named.get(value.lower(), 0x2B2D31)
|
|
107
|
+
|
|
108
|
+
async def evaluate(self, code: str) -> tuple[str, list[dict], list[dict]]:
|
|
109
|
+
try:
|
|
110
|
+
result = await self._eval(code)
|
|
111
|
+
except StopExecution as e:
|
|
112
|
+
result = str(e)
|
|
113
|
+
except CooldownError as e:
|
|
114
|
+
self._cooldown_msg = str(e)
|
|
115
|
+
result = str(e)
|
|
116
|
+
_flush_select(self)
|
|
117
|
+
_flush_row(self)
|
|
118
|
+
embeds = [eb.to_dict() for eb in self._embeds if eb.has_data()]
|
|
119
|
+
result = result.strip("\n")
|
|
120
|
+
return result, embeds, self._extra_messages
|
|
121
|
+
|
|
122
|
+
async def _eval(self, code: str) -> str:
|
|
123
|
+
functions = find_functions(code)
|
|
124
|
+
if not functions:
|
|
125
|
+
return code
|
|
126
|
+
parts = []
|
|
127
|
+
offset = 0
|
|
128
|
+
for start, end, fn_name, raw_args in functions:
|
|
129
|
+
parts.append(code[offset:start])
|
|
130
|
+
if raw_args is not None:
|
|
131
|
+
if fn_name.lower() == "addcontainer":
|
|
132
|
+
self._cv2_in_container = True
|
|
133
|
+
self._cv2_stack.append([])
|
|
134
|
+
evaluated_args_str = await self._eval_inner(raw_args)
|
|
135
|
+
self._cv2_in_container = False
|
|
136
|
+
else:
|
|
137
|
+
evaluated_args_str = await self._eval(raw_args)
|
|
138
|
+
args = split_args(evaluated_args_str)
|
|
139
|
+
else:
|
|
140
|
+
args = []
|
|
141
|
+
replacement = await self._resolve(fn_name.lower(), args, raw_args or "")
|
|
142
|
+
parts.append(replacement)
|
|
143
|
+
offset = end
|
|
144
|
+
parts.append(code[offset:])
|
|
145
|
+
return "".join(parts)
|
|
146
|
+
|
|
147
|
+
async def _eval_inner(self, code: str) -> str:
|
|
148
|
+
functions = find_functions(code)
|
|
149
|
+
if not functions:
|
|
150
|
+
return code
|
|
151
|
+
parts = []
|
|
152
|
+
offset = 0
|
|
153
|
+
for start, end, fn_name, raw_args in functions:
|
|
154
|
+
parts.append(code[offset:start])
|
|
155
|
+
if raw_args is not None:
|
|
156
|
+
evaluated_args_str = await self._eval(raw_args)
|
|
157
|
+
args = split_args(evaluated_args_str)
|
|
158
|
+
else:
|
|
159
|
+
args = []
|
|
160
|
+
replacement = await self._resolve(fn_name.lower(), args, raw_args or "")
|
|
161
|
+
parts.append(replacement)
|
|
162
|
+
offset = end
|
|
163
|
+
parts.append(code[offset:])
|
|
164
|
+
return "".join(parts)
|
|
165
|
+
|
|
166
|
+
async def _resolve(self, fn: str, args: list[str], raw: str) -> str:
|
|
167
|
+
handlers = [
|
|
168
|
+
handle_message, handle_interaction, handle_embed,
|
|
169
|
+
handle_components, handle_componentsv2, handle_logic,
|
|
170
|
+
handle_user, handle_database, handle_moderation, handle_status,
|
|
171
|
+
handle_math, handle_time, handle_random,
|
|
172
|
+
handle_http, handle_cooldown, handle_json, handle_strings,
|
|
173
|
+
]
|
|
174
|
+
|
|
175
|
+
for handler in handlers:
|
|
176
|
+
result = await handler(fn, args, raw, self)
|
|
177
|
+
if result is not None:
|
|
178
|
+
return result
|
|
179
|
+
|
|
180
|
+
for i in range(len(fn) - 1, 0, -1):
|
|
181
|
+
prefix = fn[:i]
|
|
182
|
+
suffix = fn[i:]
|
|
183
|
+
for handler in handlers:
|
|
184
|
+
result = await handler(prefix, [], "", self)
|
|
185
|
+
if result is not None:
|
|
186
|
+
return result + suffix
|
|
187
|
+
|
|
188
|
+
if raw:
|
|
189
|
+
return f"${fn}[{raw}]"
|
|
190
|
+
return f"${fn}"
|
cordscript/setup.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="cordscript",
|
|
5
|
+
version="1.0.0",
|
|
6
|
+
description="A Discord Bot library, with the mission of simplifying the use of the Discord API.",
|
|
7
|
+
long_description=open("README.md", encoding="utf-8").read(),
|
|
8
|
+
long_description_content_type="text/markdown",
|
|
9
|
+
author="Arimoto",
|
|
10
|
+
author_email="",
|
|
11
|
+
url="https://github.com/[seu-usuario]/cordscript",
|
|
12
|
+
project_urls={
|
|
13
|
+
"Documentation": "https://github.com/[seu-usuario]/cordscript#readme",
|
|
14
|
+
"Bug Reports": "https://github.com/[seu-usuario]/cordscript/issues",
|
|
15
|
+
"Source Code": "https://github.com/[seu-usuario]/cordscript",
|
|
16
|
+
},
|
|
17
|
+
license="MIT",
|
|
18
|
+
python_requires=">=3.10",
|
|
19
|
+
packages=find_packages(exclude=["tests", "*.tests", "*.tests.*", "tests.*"]),
|
|
20
|
+
install_requires=[
|
|
21
|
+
"discord.py>=2.3.0",
|
|
22
|
+
"aiohttp>=3.8.0",
|
|
23
|
+
"tinydb>=4.7.0",
|
|
24
|
+
],
|
|
25
|
+
classifiers=[
|
|
26
|
+
"Development Status :: 3 - Alpha",
|
|
27
|
+
"Intended Audience :: Developers",
|
|
28
|
+
"License :: OSI Approved :: MIT License",
|
|
29
|
+
"Programming Language :: Python :: 3",
|
|
30
|
+
"Programming Language :: Python :: 3.10",
|
|
31
|
+
"Programming Language :: Python :: 3.11",
|
|
32
|
+
"Programming Language :: Python :: 3.12",
|
|
33
|
+
"Programming Language :: Python :: 3.13",
|
|
34
|
+
"Topic :: Communications :: Chat",
|
|
35
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
36
|
+
],
|
|
37
|
+
keywords="discord bot easy",
|
|
38
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cordscript
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Home-page:
|
|
5
|
+
Author: Arimo
|
|
6
|
+
Author-email: alysonk078@gmail.com
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Requires-Dist: discord.py
|
|
11
|
+
Requires-Dist: aiohttp
|
|
12
|
+
Requires-Dist: tinydb
|
|
13
|
+
Dynamic: author
|
|
14
|
+
Dynamic: author-email
|
|
15
|
+
Dynamic: classifier
|
|
16
|
+
Dynamic: requires-dist
|
|
17
|
+
Dynamic: requires-python
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
cordscript/__init__.py,sha256=a4ZHPWsKv0Zcrh0blRGJN1YswCvSGoVg_XRpvcA-pNI,161
|
|
2
|
+
cordscript/client.py,sha256=m_IObcMaEphuFzQ_rCibuvMtnx-QCL4Vj_wm41Zt7SE,21660
|
|
3
|
+
cordscript/parser.py,sha256=MTVu6ewetq3OmNPnGpz10l_SnokjtQcKmzc50kS0rMs,7084
|
|
4
|
+
cordscript/setup.py,sha256=2hegabR2_ZIFdXzC8ThabQjLHVUndTDmlbyCPn-1iw4,1463
|
|
5
|
+
cordscript/core/__init__.py,sha256=6GBB7IiDkPZ85bhjuborlv1t6_hXKYvLkQrynNeJqeg,358
|
|
6
|
+
cordscript/core/context.py,sha256=BFCO1-A1UX6DI1LE6ic6kfLF24j1vt5OJ5ylZVHJY6M,701
|
|
7
|
+
cordscript/core/runtime.py,sha256=YbTLC2FkzRO1W5fbZ0EJ0HAf8I__dVlBoglSMbe78AU,1451
|
|
8
|
+
cordscript/core/variables.py,sha256=sd6RbI9Lvt0JbJT7B0d3Bkhzx59S29C8zUKsUprwBZI,381
|
|
9
|
+
cordscript/exceptions/__init__.py,sha256=mO4Z5NlFaDUAfbYnt-I-XvwIfpoXOnEYrjwDDX4UTpU,94
|
|
10
|
+
cordscript/exceptions/errors.py,sha256=eKDm-v70Rslnyx3G9XScZwdxkA1IlVzIsxptT3OXwBQ,120
|
|
11
|
+
cordscript/functions/__init__.py,sha256=F8fBbSieSpCpaqVpDbRN8iCqQTiGFlaRgEViuRUq2dk,875
|
|
12
|
+
cordscript/functions/database/__init__.py,sha256=-00VOswf3b-pifUqa5y1IXzSwmTFxKjnlbdYtaLeCMA,175
|
|
13
|
+
cordscript/functions/database/database.py,sha256=CT5zy9fw8-WbGl3lX0fnQaFnrVXGqGD2uvuQA0yni7s,38156
|
|
14
|
+
cordscript/functions/database/store.py,sha256=NO1z-mSv7ZNr6BLGWfyLGyOq0ahHo2kOH0Rzuz9Ga5s,2361
|
|
15
|
+
cordscript/functions/discord/__init__.py,sha256=dpMK4lgwz6upVuTwAfUqqo7CAADDwrG_znmxtDOzdak,550
|
|
16
|
+
cordscript/functions/discord/components.py,sha256=WOsMZSE_PVmNU_MqnvB2FdPNEkBwX9GZ73R9OVq91Ec,5329
|
|
17
|
+
cordscript/functions/discord/componentsv2.py,sha256=d_tIetSMAKcNWoNZdiJ_MrC3dV-jhxpBxcwj8Ni15e8,3637
|
|
18
|
+
cordscript/functions/discord/embed.py,sha256=Hs_dDI3tlt_IzHpPYwT5iW6flvTyJcjjuPp1SUNvRv0,2170
|
|
19
|
+
cordscript/functions/discord/interaction.py,sha256=-LDwTqVfEwPilhdaRu4QJ9RRtLVCxdaAYyrUHucOoc8,1448
|
|
20
|
+
cordscript/functions/discord/logic.py,sha256=22G5rVItka0iueZyFYAAYLHEViEEL1lEsNnNn-d8Fgo,3279
|
|
21
|
+
cordscript/functions/discord/message.py,sha256=J3xtBbtvmOYcS4adNsK_QvPJP7pZkc2d8WMxGx_a_6I,1873
|
|
22
|
+
cordscript/functions/discord/moderation.py,sha256=rqDEhan3mLh857_zIF7suihEvqOsK1JMMjlSxgUljHg,7375
|
|
23
|
+
cordscript/functions/discord/status.py,sha256=X7ymyjbHWs1Sq7c2dBt7phwxrGiW141qjYF2V9NaE5U,2091
|
|
24
|
+
cordscript/functions/users/__init__.py,sha256=zKsYNHzNGo5tTI4ryEzm_YG_FraSk1WYTkxZ8oINtVI,57
|
|
25
|
+
cordscript/functions/users/user.py,sha256=DRa9w9rifqNvlXkg8f3zstfHwzzhvTGnuWhOhJH_53M,3741
|
|
26
|
+
cordscript/functions/utility/__init__.py,sha256=Edq7WcM3LYsumWNMJ-tMnoKCGtsOVchJtD9NvIWfb9k,396
|
|
27
|
+
cordscript/functions/utility/cooldown.py,sha256=l5lY9WQ0QGw-0ZSlQLEOOWykBBGVYlOSpB1rSK8CGQk,1223
|
|
28
|
+
cordscript/functions/utility/http.py,sha256=Nm-lua40q9bsrEQ3cX9b3gohDc_Ihdyt52yzAul6cCs,3430
|
|
29
|
+
cordscript/functions/utility/json.py,sha256=qVZofu60GUCajjCRqrkVSDRBaYoPD2K-0eBCSyWpf0Y,8076
|
|
30
|
+
cordscript/functions/utility/math.py,sha256=8IQwDtOMh7bUTQUXLUtU8RQ_OneLmdhDgsGRhEiHHyw,3475
|
|
31
|
+
cordscript/functions/utility/random.py,sha256=wxeK6ymyN2-AMqvixJmBnTLk-05p1naEniy0zbxSw_k,936
|
|
32
|
+
cordscript/functions/utility/strings.py,sha256=K5d3OM9bpVU4AVbngZdMqUaLMDfz4zv_EJaQZoz1veI,7664
|
|
33
|
+
cordscript/functions/utility/time.py,sha256=u3r6n8hkGqc4ZdZJIqRwzqr_WEUbnzOOh1uhjmsG3ow,1389
|
|
34
|
+
cordscript-1.0.0.dist-info/METADATA,sha256=3gwViBTel0H8vQpbVbGYBRsqj4IeQ9aD8uKa1DTR8xc,418
|
|
35
|
+
cordscript-1.0.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
36
|
+
cordscript-1.0.0.dist-info/top_level.txt,sha256=OVTk5gwO8_wFSHGhXAEiEI6AwUhGf6xWGya5YcuemlM,11
|
|
37
|
+
cordscript-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cordscript
|