Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions utils/generate_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from typing import TYPE_CHECKING
from utils.helpers import format_type
from utils.helpers import indentation
from utils.helpers import StructureKind

if TYPE_CHECKING:
from lsp_schema import Notification
Expand Down Expand Up @@ -40,7 +39,7 @@ def generate_notification(notification: Notification) -> tuple[str, str]:
definition = f'class {name}(TypedDict):\n'
definition += f"{indentation}method: Literal['{method}']\n"
if params:
definition += f'{indentation}params: {format_type(params, {"root_symbol_name": ""}, StructureKind.Class)}'
definition += f'{indentation}params: {format_type(params, {"root_symbol_name": ""})}'
else:
definition += f'{indentation}params: None'
return (name, definition)
7 changes: 3 additions & 4 deletions utils/generate_requests_and_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from typing import TYPE_CHECKING
from utils.helpers import format_type
from utils.helpers import indentation
from utils.helpers import StructureKind

if TYPE_CHECKING:
from lsp_schema import Request
Expand Down Expand Up @@ -59,7 +58,7 @@ def generate_request(request: Request) -> tuple[str, str]:
definition = f'class {name}(TypedDict):\n'
definition += f"{indentation}method: Literal['{method}']\n"
if params:
definition += f'{indentation}params: {format_type(params, {"root_symbol_name": ""}, StructureKind.Class)}'
definition += f'{indentation}params: {format_type(params, {"root_symbol_name": ""})}'
else:
definition += f'{indentation}params: None'
return (name, definition)
Expand All @@ -74,7 +73,7 @@ def generate_response(request: Request) -> tuple[str, str]:
definition = f'class {name}(TypedDict):\n'
definition += f"{indentation}method: Literal['{method}']\n"
if request['messageDirection'] == 'serverToClient':
typ = format_type(params, {'root_symbol_name': ''}, StructureKind.Class) if params else None
typ = format_type(params, {'root_symbol_name': ''}) if params else None
definition += f'{indentation}params: {typ}\n'
definition += f'{indentation}result: {format_type(result, {"root_symbol_name": ""}, StructureKind.Class)}'
definition += f'{indentation}result: {format_type(result, {"root_symbol_name": ""})}'
return (name, definition)
10 changes: 4 additions & 6 deletions utils/generate_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ def to_string(structure: Structure) -> str:
return [to_string(structure) for structure in structures if not structure['name'].startswith('_')]


def get_additional_properties(
for_structure: Structure, structures: list[Structure], structure_kind: StructureKind
) -> list[FormattedProperty]:
def get_additional_properties(for_structure: Structure, structures: list[Structure]) -> list[FormattedProperty]:
"""Return properties from extended and mixin types."""
result: list[FormattedProperty] = []
additional_structures = for_structure.get('extends') or []
Expand All @@ -35,16 +33,16 @@ def get_additional_properties(
raise Exception(error, additional_structure['kind'])
structure = next(structure for structure in structures if structure['name'] == additional_structure['name'])
if structure:
properties = get_formatted_properties(structure['properties'], structure['name'], structure_kind)
properties = get_formatted_properties(structure['properties'], structure['name'])
result.extend(properties)
return result


def generate_structure(structure: Structure, structures: list[Structure], structure_kind: StructureKind) -> str:
result = ''
symbol_name = structure['name']
properties = get_formatted_properties(structure['properties'], structure['name'], structure_kind)
additional_properties = get_additional_properties(structure, structures, structure_kind)
properties = get_formatted_properties(structure['properties'], structure['name'])
additional_properties = get_additional_properties(structure, structures)

# add extended properties
taken_property_names = [p['name'] for p in properties]
Expand Down
3 changes: 1 addition & 2 deletions utils/generate_type_aliases.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from typing import TYPE_CHECKING
from utils.helpers import format_comment
from utils.helpers import format_type
from utils.helpers import StructureKind

if TYPE_CHECKING:
from lsp_schema import TypeAlias
Expand All @@ -16,7 +15,7 @@ def to_string(type_alias: TypeAlias) -> str:
if symbol_name in overrides:
value = overrides[symbol_name]
else:
value = format_type(type_alias['type'], {'root_symbol_name': symbol_name}, StructureKind.Class)
value = format_type(type_alias['type'], {'root_symbol_name': symbol_name})
result = f"""
{symbol_name}: TypeAlias = {value}"""
if documentation:
Expand Down
56 changes: 9 additions & 47 deletions utils/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from enum import Enum
from typing import Any
from typing import ClassVar
from typing import TYPE_CHECKING
from typing import TypedDict
import keyword
Expand Down Expand Up @@ -41,30 +40,12 @@ def format_comment(text: str | None, indent: str = '') -> str:
new_literal_structures: set[str] = set()


class SymbolNameTracker:
symbols: ClassVar[dict[str, int]] = {
# key: symbol name
# value: symbol count
}

@classmethod
def get_symbol_id(cls, symbol_name: str) -> int:
count = SymbolNameTracker.symbols.get(symbol_name) or 1
SymbolNameTracker.symbols[symbol_name] = count + 1
return count

@classmethod
def clear(cls) -> None:
SymbolNameTracker.symbols.clear()


def get_new_literal_structures() -> list[str]:
return sorted(new_literal_structures)


def reset_new_literal_structures() -> None:
new_literal_structures.clear()
SymbolNameTracker.clear()


class StructureKind(Enum):
Expand All @@ -76,50 +57,33 @@ class FormatTypeContext(TypedDict):
root_symbol_name: str


def format_type(typ: EveryType, context: FormatTypeContext, preferred_structure_kind: StructureKind) -> str:
def format_type(typ: EveryType, context: FormatTypeContext) -> str:
result = 'Any'
if typ['kind'] == 'base':
return format_base_types(typ)
if typ['kind'] == 'reference':
literal_symbol_name = typ['name']
return f"'{literal_symbol_name}'"
if typ['kind'] == 'array':
literal_symbol_name = format_type(typ['element'], context, preferred_structure_kind)
literal_symbol_name = format_type(typ['element'], context)
return f'List[{literal_symbol_name}]'
if typ['kind'] == 'map':
key = format_base_types(typ['key'])
value = format_type(typ['value'], {'root_symbol_name': key}, preferred_structure_kind)
value = format_type(typ['value'], {'root_symbol_name': key})
return f'Dict[{key}, {value}]'
if typ['kind'] == 'and':
pass
elif typ['kind'] == 'or':
union = [format_type(item, context, preferred_structure_kind) for item in typ['items']]
union = [format_type(item, context) for item in typ['items']]
return f'Union[{", ".join(union)}]'
elif typ['kind'] == 'tuple':
union = [format_type(item, context, preferred_structure_kind) for item in typ['items']]
union = [format_type(item, context) for item in typ['items']]
return f'list[{" | ".join(set(union))}]'
elif typ['kind'] == 'literal':
if not typ['value']['properties']:
return 'Dict[str, LSPAny]'
root_symbol_name = capitalize(context['root_symbol_name'])
literal_symbol_name = f'__{root_symbol_name}_Type'
symbol_id = SymbolNameTracker.get_symbol_id(literal_symbol_name)
literal_symbol_name += f'_{symbol_id}'
properties = get_formatted_properties(typ['value']['properties'], root_symbol_name, preferred_structure_kind)
if preferred_structure_kind == StructureKind.Function:
formatted_properties = format_dict_properties(properties)
new_literal_structures.add(f"""
{literal_symbol_name} = TypedDict('{literal_symbol_name}', {{
{indentation}{formatted_properties}
}})
""")
else:
formatted_properties = format_class_properties(properties)
new_literal_structures.add(f"""
class {literal_symbol_name}(TypedDict):
{indentation}{formatted_properties or 'pass'}
""")
return f"'{literal_symbol_name}'"
msg = 'Unsupported case, none of the cases in LSP schema need this currently!'
raise Exception(msg)
elif typ['kind'] == 'stringLiteral':
return f"Literal['{typ['value']}']"
elif typ['kind'] == 'integerLiteral' or typ['kind'] == 'booleanLiteral':
Expand Down Expand Up @@ -147,13 +111,11 @@ class FormattedProperty(TypedDict):
documentation: str


def get_formatted_properties(
properties: list[Property], root_symbol_name: str, preferred_structure_kind: StructureKind
) -> list[FormattedProperty]:
def get_formatted_properties(properties: list[Property], root_symbol_name: str) -> list[FormattedProperty]:
result: list[FormattedProperty] = []
for p in properties:
key = p['name']
value = format_type(p['type'], {'root_symbol_name': root_symbol_name + '_' + key}, preferred_structure_kind)
value = format_type(p['type'], {'root_symbol_name': root_symbol_name + '_' + key})
if p.get('optional'):
value = f'NotRequired[{value}]'
documentation = p.get('documentation') or ''
Expand Down