-
-
Notifications
You must be signed in to change notification settings - Fork 186
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c4770d6
commit 0ac4752
Showing
9 changed files
with
2,708 additions
and
1 deletion.
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 |
---|---|---|
|
@@ -7,3 +7,4 @@ dev | |
test.py | ||
.env | ||
build | ||
badges.py |
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 |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# TikTokLive TypeScript Declarations | ||
|
||
A potential use-case for TikTokLive is to create a web server that forwards events from Python to your front-end TypeScript application. | ||
|
||
In this case, type definitions for TikTokLive events are useful. After all, what's the point of a strictly typed language without types? | ||
|
||
This module generates typedefs for TikTokLive to put into your project. | ||
|
||
See the [package](package) folder for the NPM package `@TikTokLive/types`. |
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,165 @@ | ||
from typing import Type, List, cast, Union, get_type_hints, TypedDict, Optional, Dict | ||
|
||
import betterproto | ||
import jinja2 | ||
|
||
import TikTokLive.proto.custom_proto as custom_proto | ||
import TikTokLive.proto.tiktok_proto as tiktok_proto | ||
from TikTokLive.events import Event | ||
|
||
EventsList: List[Type[Event]] = cast(Union, Event).__args__ | ||
|
||
InputClassMapping: Type = TypedDict( | ||
'InputClassMapping', | ||
{ | ||
"name": str, | ||
"mappings": dict[str, Type], | ||
"super": Optional[Type[betterproto.Message]] | ||
} | ||
) | ||
|
||
InputEnumMapping: Type = TypedDict( | ||
'InputEnumMapping', | ||
{ | ||
"name": str, | ||
"mappings": dict[str, int] | ||
} | ||
) | ||
|
||
PrimitiveMappings: Dict[Type, str] = { | ||
str: "string", | ||
int: "number", | ||
float: "number", | ||
bool: "boolean", | ||
bytes: "unknown" | ||
} | ||
|
||
|
||
def process_event_class(c: Type[Event]) -> InputClassMapping: | ||
""" | ||
Generate a type def of an event | ||
:param c: The event class to check | ||
:return: The type def | ||
""" | ||
|
||
base_message = None | ||
for base in c.__bases__: | ||
if issubclass(base, betterproto.Message): | ||
base_message = base | ||
|
||
bases_hints = get_type_hints(base_message) if base_message else {} | ||
mappings: dict[str, Type] = {} | ||
|
||
for member_name, member_type in get_type_hints(c).items(): | ||
|
||
if member_name.startswith("_"): | ||
continue | ||
|
||
if member_name in bases_hints and member_type == bases_hints[member_name]: | ||
continue | ||
|
||
mappings[member_name] = member_type | ||
|
||
return {'mappings': mappings, 'super': base_message, 'name': c.__name__} | ||
|
||
|
||
def process_proto_class(c: Type[betterproto.Message]) -> InputClassMapping: | ||
mappings: dict[str, Type] = {} | ||
|
||
# Look for instances of subclassing | ||
base_message = None | ||
for base in c.__bases__: | ||
if base != betterproto.Message: | ||
base_message = base | ||
|
||
bases_hints = get_type_hints(base_message) if base_message else {} | ||
|
||
for member_name, member_type in get_type_hints(c).items(): | ||
|
||
if member_name.startswith("_"): | ||
continue | ||
|
||
if member_name in bases_hints and member_type == bases_hints[member_name]: | ||
continue | ||
|
||
mappings[member_name] = member_type | ||
|
||
return {'mappings': mappings, 'super': base_message, 'name': c.__name__} | ||
|
||
|
||
def process_proto_enum(c: Type[betterproto.Enum]) -> InputEnumMapping: | ||
return { | ||
'mappings': {member.name: member.value for member in c}, | ||
'name': c.__name__ | ||
} | ||
|
||
|
||
def module_classes(module) -> List[Type]: | ||
md = module.__dict__ | ||
return [ | ||
md[c] for c in md if ( | ||
isinstance(md[c], type) and md[c].__module__ == module.__name__ | ||
) | ||
] | ||
|
||
|
||
def build_ts_defs( | ||
enums: List[InputEnumMapping], | ||
classes: List[InputClassMapping], | ||
events: List[InputClassMapping], | ||
primitives: Dict[Type, str] | ||
) -> str: | ||
env: jinja2.Environment = jinja2.Environment( | ||
trim_blocks=True, | ||
lstrip_blocks=True, | ||
loader=jinja2.FileSystemLoader('./'), | ||
) | ||
|
||
template = jinja2.Template = env.get_template('ts_template.jinja2') | ||
|
||
return template.render({ | ||
'enums': enums, | ||
'classes': classes, | ||
'events': events, | ||
'primitives': primitives | ||
}) | ||
|
||
|
||
if __name__ == '__main__': | ||
|
||
all_proto: list[Type] = [ | ||
*module_classes(tiktok_proto), | ||
*module_classes(custom_proto) | ||
] | ||
|
||
enum_defs: list[InputEnumMapping] = [] | ||
class_defs: list[InputClassMapping] = [] | ||
|
||
for class_meta in all_proto: | ||
|
||
if issubclass(class_meta, betterproto.Enum): | ||
enum_defs.append( | ||
process_proto_enum(class_meta) | ||
) | ||
|
||
if issubclass(class_meta, betterproto.Message): | ||
class_defs.append( | ||
process_proto_class(class_meta) | ||
) | ||
|
||
event_defs: list[InputClassMapping] = [] | ||
|
||
for class_meta in EventsList: | ||
event_defs.append( | ||
process_event_class(class_meta) | ||
) | ||
|
||
with open("./package/TikTokLive.d.ts", "w") as file: | ||
file.write(build_ts_defs( | ||
enums=enum_defs, | ||
classes=class_defs, | ||
events=event_defs, | ||
primitives=PrimitiveMappings | ||
)) |
Oops, something went wrong.