teloce-py 0.1.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.
Files changed (131) hide show
  1. teloce/__init__.py +17 -0
  2. teloce/__main__.py +13 -0
  3. teloce/ast/__init__.py +87 -0
  4. teloce/ast/components.py +77 -0
  5. teloce/ast/elements.py +84 -0
  6. teloce/ast/expressions.py +151 -0
  7. teloce/ast/nodes.py +271 -0
  8. teloce/ast/visitors.py +246 -0
  9. teloce/build/__init__.py +37 -0
  10. teloce/build/assets.py +128 -0
  11. teloce/build/builder.py +292 -0
  12. teloce/build/bundler.py +153 -0
  13. teloce/build/manifest.py +89 -0
  14. teloce/build/writer.py +86 -0
  15. teloce/cli/__init__.py +25 -0
  16. teloce/cli/benchmark.py +62 -0
  17. teloce/cli/build.py +81 -0
  18. teloce/cli/create.py +281 -0
  19. teloce/cli/debug.py +72 -0
  20. teloce/cli/dev.py +101 -0
  21. teloce/cli/doctor.py +99 -0
  22. teloce/cli/lint.py +148 -0
  23. teloce/cli/main.py +223 -0
  24. teloce/cli/server.py +176 -0
  25. teloce/cli/watch.py +98 -0
  26. teloce/compiler/__init__.py +31 -0
  27. teloce/compiler/compiler.py +266 -0
  28. teloce/compiler/diagnostics.py +129 -0
  29. teloce/compiler/generator.py +518 -0
  30. teloce/compiler/lexer.py +515 -0
  31. teloce/compiler/optimizer.py +115 -0
  32. teloce/compiler/parser.py +329 -0
  33. teloce/compiler/source_map.py +79 -0
  34. teloce/compiler/transformer.py +71 -0
  35. teloce/components/__init__.py +17 -0
  36. teloce/components/dependency_graph.py +177 -0
  37. teloce/components/imports.py +118 -0
  38. teloce/components/registry.py +108 -0
  39. teloce/components/resolver.py +107 -0
  40. teloce/css/__init__.py +20 -0
  41. teloce/css/generator.py +160 -0
  42. teloce/css/hashing.py +73 -0
  43. teloce/css/modules.py +30 -0
  44. teloce/css/parser.py +395 -0
  45. teloce/css/scoped.py +179 -0
  46. teloce/debug/__init__.py +18 -0
  47. teloce/debug/errors.py +195 -0
  48. teloce/debug/formatter.py +185 -0
  49. teloce/debug/suggestions.py +230 -0
  50. teloce/directives/__init__.py +27 -0
  51. teloce/directives/base.py +135 -0
  52. teloce/directives/bind.py +502 -0
  53. teloce/directives/events.py +126 -0
  54. teloce/directives/for_.py +95 -0
  55. teloce/directives/if_.py +105 -0
  56. teloce/directives/model.py +52 -0
  57. teloce/directives/registry.py +69 -0
  58. teloce/directives/show.py +62 -0
  59. teloce/expressions/__init__.py +41 -0
  60. teloce/expressions/ast.py +118 -0
  61. teloce/expressions/generator.py +132 -0
  62. teloce/expressions/lexer.py +530 -0
  63. teloce/expressions/parser.py +488 -0
  64. teloce/filters/__init__.py +22 -0
  65. teloce/filters/arrays.py +112 -0
  66. teloce/filters/dates.py +142 -0
  67. teloce/filters/numbers.py +98 -0
  68. teloce/filters/objects.py +89 -0
  69. teloce/filters/registry.py +98 -0
  70. teloce/filters/strings.py +171 -0
  71. teloce/javascript/__init__.py +21 -0
  72. teloce/javascript/dom.py +140 -0
  73. teloce/javascript/exports.py +49 -0
  74. teloce/javascript/generator.py +250 -0
  75. teloce/javascript/helpers.py +218 -0
  76. teloce/javascript/imports.py +95 -0
  77. teloce/javascript/module.py +63 -0
  78. teloce/plugins/__init__.py +21 -0
  79. teloce/plugins/api.py +120 -0
  80. teloce/plugins/directives.py +42 -0
  81. teloce/plugins/filters.py +41 -0
  82. teloce/plugins/hooks.py +81 -0
  83. teloce/plugins/registry.py +113 -0
  84. teloce/project/__init__.py +17 -0
  85. teloce/project/configuration.py +142 -0
  86. teloce/project/discovery.py +160 -0
  87. teloce/project/paths.py +122 -0
  88. teloce/project/scanner.py +126 -0
  89. teloce/router/__init__.py +13 -0
  90. teloce/router/compiler.py +161 -0
  91. teloce/router/generator.py +166 -0
  92. teloce/runtime/__init__.py +8 -0
  93. teloce/runtime/component.js +21 -0
  94. teloce/runtime/computed.js +2 -0
  95. teloce/runtime/dom.js +119 -0
  96. teloce/runtime/effects.js +2 -0
  97. teloce/runtime/events.js +4 -0
  98. teloce/runtime/lifecycle.js +3 -0
  99. teloce/runtime/props.js +7 -0
  100. teloce/runtime/reactivity.js +16 -0
  101. teloce/runtime/runtime.js +11 -0
  102. teloce/runtime/scheduler.js +40 -0
  103. teloce/runtime/signals.js +131 -0
  104. teloce/runtime/slots.js +4 -0
  105. teloce/runtime/standalone.js +221 -0
  106. teloce/sfc/__init__.py +25 -0
  107. teloce/sfc/component.py +95 -0
  108. teloce/sfc/parser.py +289 -0
  109. teloce/sfc/script.py +1009 -0
  110. teloce/sfc/sections.py +46 -0
  111. teloce/sfc/style.py +582 -0
  112. teloce/sfc/template.py +66 -0
  113. teloce/template/__init__.py +29 -0
  114. teloce/template/components.py +122 -0
  115. teloce/template/conditions.py +75 -0
  116. teloce/template/directives.py +111 -0
  117. teloce/template/expressions.py +398 -0
  118. teloce/template/interpolation.py +74 -0
  119. teloce/template/lexer.py +421 -0
  120. teloce/template/loops.py +92 -0
  121. teloce/template/parser.py +101 -0
  122. teloce/template/slots.py +66 -0
  123. teloce/version.py +6 -0
  124. teloce/watcher/__init__.py +13 -0
  125. teloce/watcher/watcher.py +174 -0
  126. teloce_py-0.1.0.dist-info/METADATA +192 -0
  127. teloce_py-0.1.0.dist-info/RECORD +131 -0
  128. teloce_py-0.1.0.dist-info/WHEEL +5 -0
  129. teloce_py-0.1.0.dist-info/entry_points.txt +2 -0
  130. teloce_py-0.1.0.dist-info/licenses/LICENSE +22 -0
  131. teloce_py-0.1.0.dist-info/top_level.txt +1 -0
teloce/__init__.py ADDED
@@ -0,0 +1,17 @@
1
+ """
2
+ Teloce-Py - A Python compiler for Teloce .vel Single File Components
3
+
4
+ Teloce-Py transforms .vel files into self-contained vanilla JavaScript
5
+ without requiring Node.js, npm, or a CDN.
6
+ """
7
+
8
+ from teloce.version import __version__
9
+
10
+ __all__ = [
11
+ "__version__",
12
+ "compile",
13
+ "compile_file",
14
+ "compile_project",
15
+ ]
16
+
17
+ from teloce.compiler.compiler import compile, compile_file, compile_project
teloce/__main__.py ADDED
@@ -0,0 +1,13 @@
1
+ """
2
+ Teloce-Py command-line entry point.
3
+
4
+ Usage:
5
+ python -m teloce [command] [options]
6
+ """
7
+
8
+ import sys
9
+
10
+ from teloce.cli.main import main
11
+
12
+ if __name__ == "__main__":
13
+ sys.exit(main())
teloce/ast/__init__.py ADDED
@@ -0,0 +1,87 @@
1
+ """
2
+ AST (Abstract Syntax Tree) package.
3
+
4
+ Defines AST nodes for Teloce templates.
5
+ """
6
+
7
+ from teloce.ast.nodes import (
8
+ ASTNode,
9
+ NodeType,
10
+ ElementNode,
11
+ TextNode,
12
+ InterpolationNode,
13
+ ForNode,
14
+ IfNode,
15
+ ElseNode,
16
+ EventNode,
17
+ BindingNode,
18
+ ComponentNode,
19
+ SlotNode,
20
+ FragmentNode,
21
+ AttributeNode,
22
+ CommentNode,
23
+ DoctypeNode,
24
+ )
25
+
26
+ from teloce.ast.expressions import (
27
+ ExpressionNode,
28
+ IdentifierNode,
29
+ LiteralNode,
30
+ BinaryNode,
31
+ UnaryNode,
32
+ CallNode,
33
+ MemberNode,
34
+ )
35
+
36
+ from teloce.ast.elements import (
37
+ ElementFactory,
38
+ VoidElement,
39
+ ContainerElement,
40
+ )
41
+
42
+ from teloce.ast.components import (
43
+ ComponentReference,
44
+ ComponentSlot,
45
+ ComponentProp,
46
+ )
47
+
48
+ from teloce.ast.visitors import (
49
+ ASTVisitor,
50
+ ASTTransformer,
51
+ ASTPrinter,
52
+ )
53
+
54
+ __all__ = [
55
+ "ASTNode",
56
+ "NodeType",
57
+ "ElementNode",
58
+ "TextNode",
59
+ "InterpolationNode",
60
+ "ForNode",
61
+ "IfNode",
62
+ "ElseNode",
63
+ "EventNode",
64
+ "BindingNode",
65
+ "ComponentNode",
66
+ "SlotNode",
67
+ "FragmentNode",
68
+ "AttributeNode",
69
+ "CommentNode",
70
+ "DoctypeNode",
71
+ "ExpressionNode",
72
+ "IdentifierNode",
73
+ "LiteralNode",
74
+ "BinaryNode",
75
+ "UnaryNode",
76
+ "CallNode",
77
+ "MemberNode",
78
+ "ElementFactory",
79
+ "VoidElement",
80
+ "ContainerElement",
81
+ "ComponentReference",
82
+ "ComponentSlot",
83
+ "ComponentProp",
84
+ "ASTVisitor",
85
+ "ASTTransformer",
86
+ "ASTPrinter",
87
+ ]
@@ -0,0 +1,77 @@
1
+ """
2
+ Component AST nodes.
3
+
4
+ Defines nodes for custom components and component-related structures.
5
+ """
6
+
7
+ from dataclasses import dataclass, field
8
+ from typing import List, Optional, Dict, Any
9
+
10
+ from teloce.ast.nodes import ASTNode, NodeType
11
+
12
+
13
+ @dataclass(init=False)
14
+ class ComponentReference(ASTNode):
15
+ """
16
+ Reference to a custom component.
17
+ """
18
+ name: str
19
+ props: Dict[str, str] = field(default_factory=dict)
20
+ children: List[ASTNode] = field(default_factory=list)
21
+ slots: Dict[str, List[ASTNode]] = field(default_factory=dict)
22
+
23
+ def __init__(self, name: str, props: Dict[str, str] = None,
24
+ children: List[ASTNode] = None,
25
+ slots: Dict[str, List[ASTNode]] = None,
26
+ line: int = 0, column: int = 0):
27
+ super().__init__(NodeType.COMPONENT, line, column)
28
+ self.name = name
29
+ self.props = props or {}
30
+ self.children = children or []
31
+ self.slots = slots or {}
32
+
33
+ def accept(self, visitor):
34
+ return visitor.visit_component(self)
35
+
36
+
37
+ @dataclass(init=False)
38
+ class ComponentSlot(ASTNode):
39
+ """
40
+ Slot definition inside a component.
41
+ """
42
+ name: str = "default"
43
+ fallback: List[ASTNode] = field(default_factory=list)
44
+
45
+ def __init__(self, name: str = "default", fallback: List[ASTNode] = None,
46
+ line: int = 0, column: int = 0):
47
+ super().__init__(NodeType.SLOT, line, column)
48
+ self.name = name
49
+ self.fallback = fallback or []
50
+
51
+ def accept(self, visitor):
52
+ return visitor.visit_slot(self)
53
+
54
+
55
+ @dataclass(init=False)
56
+ class ComponentProp(ASTNode):
57
+ """
58
+ Prop definition for a component.
59
+ """
60
+ name: str
61
+ type: Optional[str] = None
62
+ required: bool = False
63
+ default: Any = None
64
+ validator: Optional[str] = None
65
+
66
+ def __init__(self, name: str, type: str = None, required: bool = False,
67
+ default: Any = None, validator: str = None,
68
+ line: int = 0, column: int = 0):
69
+ super().__init__(NodeType.ATTRIBUTE, line, column)
70
+ self.name = name
71
+ self.type = type
72
+ self.required = required
73
+ self.default = default
74
+ self.validator = validator
75
+
76
+ def accept(self, visitor):
77
+ return visitor.visit_attribute(self)
teloce/ast/elements.py ADDED
@@ -0,0 +1,84 @@
1
+ """
2
+ Element factory and utilities.
3
+
4
+ Provides utilities for creating and working with element nodes.
5
+ """
6
+
7
+ from typing import List, Optional, Set
8
+
9
+ from teloce.ast.nodes import ElementNode
10
+
11
+
12
+ # HTML void elements (self-closing)
13
+ VOID_ELEMENTS = {
14
+ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
15
+ 'link', 'meta', 'param', 'source', 'track', 'wbr',
16
+ 'command', 'keygen', 'menuitem'
17
+ }
18
+
19
+ # Container elements (can have children)
20
+ CONTAINER_ELEMENTS = {
21
+ 'div', 'span', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
22
+ 'a', 'button', 'form', 'input', 'label', 'select', 'textarea',
23
+ 'ul', 'ol', 'li', 'table', 'tr', 'td', 'th', 'thead', 'tbody',
24
+ 'section', 'article', 'header', 'footer', 'nav', 'main', 'aside',
25
+ 'figure', 'figcaption', 'blockquote', 'pre', 'code', 'em', 'strong',
26
+ 'i', 'b', 'u', 's', 'small', 'mark', 'del', 'ins', 'sub', 'sup',
27
+ 'iframe', 'video', 'audio', 'canvas', 'svg', 'template'
28
+ }
29
+
30
+
31
+ class ElementFactory:
32
+ """
33
+ Factory for creating element nodes.
34
+ """
35
+
36
+ @staticmethod
37
+ def is_void(tag: str) -> bool:
38
+ """Check if a tag is a void element."""
39
+ return tag.lower() in VOID_ELEMENTS
40
+
41
+ @staticmethod
42
+ def is_container(tag: str) -> bool:
43
+ """Check if a tag is a container element."""
44
+ return tag.lower() in CONTAINER_ELEMENTS or tag.lower() not in VOID_ELEMENTS
45
+
46
+ @staticmethod
47
+ def create(tag: str, attributes: dict = None,
48
+ children: List = None, line: int = 0, column: int = 0) -> ElementNode:
49
+ """Create an element node."""
50
+ return ElementNode(tag, attributes, children=children or [], line=line, column=column)
51
+
52
+ @staticmethod
53
+ def create_void(tag: str, attributes: dict = None,
54
+ line: int = 0, column: int = 0) -> ElementNode:
55
+ """Create a void (self-closing) element."""
56
+ return ElementNode(tag, attributes, children=[], line=line, column=column)
57
+
58
+
59
+ class VoidElement:
60
+ """
61
+ Represents a void (self-closing) HTML element.
62
+ """
63
+
64
+ @staticmethod
65
+ def is_void(tag: str) -> bool:
66
+ return tag.lower() in VOID_ELEMENTS
67
+
68
+ @staticmethod
69
+ def get_all() -> Set[str]:
70
+ return VOID_ELEMENTS.copy()
71
+
72
+
73
+ class ContainerElement:
74
+ """
75
+ Represents a container HTML element that can have children.
76
+ """
77
+
78
+ @staticmethod
79
+ def is_container(tag: str) -> bool:
80
+ return tag.lower() in CONTAINER_ELEMENTS or tag.lower() not in VOID_ELEMENTS
81
+
82
+ @staticmethod
83
+ def get_all() -> Set[str]:
84
+ return CONTAINER_ELEMENTS.copy()
@@ -0,0 +1,151 @@
1
+ """
2
+ Expression AST nodes.
3
+
4
+ Defines AST nodes for expressions used in templates.
5
+ """
6
+
7
+ from dataclasses import dataclass
8
+ from typing import List, Optional, Any
9
+ from enum import Enum, auto
10
+
11
+
12
+ class ExpressionType(Enum):
13
+ """Types of expression nodes."""
14
+ IDENTIFIER = auto()
15
+ LITERAL = auto()
16
+ BINARY = auto()
17
+ UNARY = auto()
18
+ CALL = auto()
19
+ MEMBER = auto()
20
+ ARRAY = auto()
21
+ OBJECT = auto()
22
+
23
+
24
+ @dataclass
25
+ class ExpressionNode:
26
+ """Base class for expression nodes."""
27
+ type: ExpressionType
28
+ line: int = 0
29
+ column: int = 0
30
+
31
+
32
+ @dataclass(init=False)
33
+ class IdentifierNode(ExpressionNode):
34
+ """Identifier expression node."""
35
+ name: str
36
+
37
+ def __init__(self, name: str, line: int = 0, column: int = 0):
38
+ super().__init__(ExpressionType.IDENTIFIER, line, column)
39
+ self.name = name
40
+
41
+ def __repr__(self) -> str:
42
+ return f"Identifier({self.name})"
43
+
44
+
45
+ @dataclass(init=False)
46
+ class LiteralNode(ExpressionNode):
47
+ """Literal value expression node."""
48
+ value: Any
49
+
50
+ def __init__(self, value: Any, line: int = 0, column: int = 0):
51
+ super().__init__(ExpressionType.LITERAL, line, column)
52
+ self.value = value
53
+
54
+ def __repr__(self) -> str:
55
+ return f"Literal({repr(self.value)})"
56
+
57
+
58
+ @dataclass(init=False)
59
+ class BinaryNode(ExpressionNode):
60
+ """Binary operation expression node."""
61
+ left: ExpressionNode
62
+ operator: str
63
+ right: ExpressionNode
64
+
65
+ def __init__(self, left: ExpressionNode, operator: str,
66
+ right: ExpressionNode, line: int = 0, column: int = 0):
67
+ super().__init__(ExpressionType.BINARY, line, column)
68
+ self.left = left
69
+ self.operator = operator
70
+ self.right = right
71
+
72
+ def __repr__(self) -> str:
73
+ return f"Binary({self.left} {self.operator} {self.right})"
74
+
75
+
76
+ @dataclass(init=False)
77
+ class UnaryNode(ExpressionNode):
78
+ """Unary operation expression node."""
79
+ operator: str
80
+ operand: ExpressionNode
81
+
82
+ def __init__(self, operator: str, operand: ExpressionNode,
83
+ line: int = 0, column: int = 0):
84
+ super().__init__(ExpressionType.UNARY, line, column)
85
+ self.operator = operator
86
+ self.operand = operand
87
+
88
+ def __repr__(self) -> str:
89
+ return f"Unary({self.operator}{self.operand})"
90
+
91
+
92
+ @dataclass(init=False)
93
+ class CallNode(ExpressionNode):
94
+ """Function call expression node."""
95
+ callee: ExpressionNode
96
+ arguments: List[ExpressionNode]
97
+
98
+ def __init__(self, callee: ExpressionNode, arguments: List[ExpressionNode] = None,
99
+ line: int = 0, column: int = 0):
100
+ super().__init__(ExpressionType.CALL, line, column)
101
+ self.callee = callee
102
+ self.arguments = arguments or []
103
+
104
+ def __repr__(self) -> str:
105
+ return f"Call({self.callee}, {self.arguments})"
106
+
107
+
108
+ @dataclass(init=False)
109
+ class MemberNode(ExpressionNode):
110
+ """Member access expression node."""
111
+ object: ExpressionNode
112
+ property: str
113
+ computed: bool = False
114
+
115
+ def __init__(self, object: ExpressionNode, property: str,
116
+ computed: bool = False, line: int = 0, column: int = 0):
117
+ super().__init__(ExpressionType.MEMBER, line, column)
118
+ self.object = object
119
+ self.property = property
120
+ self.computed = computed
121
+
122
+ def __repr__(self) -> str:
123
+ return f"Member({self.object}.{self.property})"
124
+
125
+
126
+ @dataclass(init=False)
127
+ class ArrayNode(ExpressionNode):
128
+ """Array literal expression node."""
129
+ elements: List[ExpressionNode]
130
+
131
+ def __init__(self, elements: List[ExpressionNode] = None,
132
+ line: int = 0, column: int = 0):
133
+ super().__init__(ExpressionType.ARRAY, line, column)
134
+ self.elements = elements or []
135
+
136
+ def __repr__(self) -> str:
137
+ return f"Array({self.elements})"
138
+
139
+
140
+ @dataclass(init=False)
141
+ class ObjectNode(ExpressionNode):
142
+ """Object literal expression node."""
143
+ properties: List[tuple]
144
+
145
+ def __init__(self, properties: List[tuple] = None,
146
+ line: int = 0, column: int = 0):
147
+ super().__init__(ExpressionType.OBJECT, line, column)
148
+ self.properties = properties or []
149
+
150
+ def __repr__(self) -> str:
151
+ return f"Object({self.properties})"
teloce/ast/nodes.py ADDED
@@ -0,0 +1,271 @@
1
+ """
2
+ AST node definitions for Teloce templates.
3
+
4
+ Defines all node types used in the Abstract Syntax Tree.
5
+ """
6
+
7
+ from enum import Enum, auto
8
+ from dataclasses import dataclass, field
9
+ from typing import List, Optional, Any, Dict
10
+
11
+
12
+ class NodeType(Enum):
13
+ """Types of AST nodes."""
14
+ ELEMENT = auto()
15
+ TEXT = auto()
16
+ INTERPOLATION = auto()
17
+ FOR = auto()
18
+ IF = auto()
19
+ ELSE = auto()
20
+ EVENT = auto()
21
+ BINDING = auto()
22
+ COMPONENT = auto()
23
+ SLOT = auto()
24
+ FRAGMENT = auto()
25
+ ATTRIBUTE = auto()
26
+ COMMENT = auto()
27
+ DOCTYPE = auto()
28
+
29
+
30
+ @dataclass
31
+ class ASTNode:
32
+ """Base class for all AST nodes."""
33
+ type: NodeType
34
+ line: int = 0
35
+ column: int = 0
36
+
37
+ def accept(self, visitor):
38
+ """Accept a visitor."""
39
+ method_name = f"visit_{self.type.name.lower()}"
40
+ method = getattr(visitor, method_name, None)
41
+ if method:
42
+ return method(self)
43
+ return visitor.visit_default(self)
44
+
45
+
46
+ @dataclass(init=False)
47
+ class ElementNode(ASTNode):
48
+ """HTML element node."""
49
+ tag: str
50
+ attributes: Dict[str, str] = field(default_factory=dict)
51
+ events: List['EventNode'] = field(default_factory=list)
52
+ bindings: List['BindingNode'] = field(default_factory=list)
53
+ children: List[ASTNode] = field(default_factory=list)
54
+
55
+ def __init__(self, tag: str, attributes: Dict[str, str] = None,
56
+ events: List['EventNode'] = None,
57
+ bindings: List['BindingNode'] = None,
58
+ children: List[ASTNode] = None,
59
+ line: int = 0, column: int = 0):
60
+ super().__init__(NodeType.ELEMENT, line, column)
61
+ self.tag = tag
62
+ self.attributes = attributes or {}
63
+ self.events = events or []
64
+ self.bindings = bindings or []
65
+ self.children = children or []
66
+
67
+ def accept(self, visitor):
68
+ return visitor.visit_element(self)
69
+
70
+
71
+ @dataclass(init=False)
72
+ class TextNode(ASTNode):
73
+ """Plain text node."""
74
+ value: str
75
+
76
+ def __init__(self, value: str, line: int = 0, column: int = 0):
77
+ super().__init__(NodeType.TEXT, line, column)
78
+ self.value = value
79
+
80
+ def accept(self, visitor):
81
+ return visitor.visit_text(self)
82
+
83
+
84
+ @dataclass(init=False)
85
+ class InterpolationNode(ASTNode):
86
+ """{{ expression }} interpolation node."""
87
+ expression: str
88
+
89
+ def __init__(self, expression: str, line: int = 0, column: int = 0):
90
+ super().__init__(NodeType.INTERPOLATION, line, column)
91
+ self.expression = expression
92
+
93
+ def accept(self, visitor):
94
+ return visitor.visit_interpolation(self)
95
+
96
+
97
+ @dataclass(init=False)
98
+ class ForNode(ASTNode):
99
+ """For loop directive node."""
100
+ item: str
101
+ collection: str
102
+ key: str = ""
103
+ children: List[ASTNode] = field(default_factory=list)
104
+
105
+ def __init__(self, item: str, collection: str, key: str = "",
106
+ children: List[ASTNode] = None,
107
+ line: int = 0, column: int = 0):
108
+ super().__init__(NodeType.FOR, line, column)
109
+ self.item = item
110
+ self.collection = collection
111
+ self.key = key
112
+ self.children = children or []
113
+
114
+ def accept(self, visitor):
115
+ return visitor.visit_for(self)
116
+
117
+
118
+ @dataclass(init=False)
119
+ class IfNode(ASTNode):
120
+ """If directive node."""
121
+ condition: str
122
+ children: List[ASTNode] = field(default_factory=list)
123
+ else_children: List[ASTNode] = field(default_factory=list)
124
+
125
+ def __init__(self, condition: str, children: List[ASTNode] = None,
126
+ else_children: List[ASTNode] = None,
127
+ line: int = 0, column: int = 0):
128
+ super().__init__(NodeType.IF, line, column)
129
+ self.condition = condition
130
+ self.children = children or []
131
+ self.else_children = else_children or []
132
+
133
+ def accept(self, visitor):
134
+ return visitor.visit_if(self)
135
+
136
+
137
+ @dataclass(init=False)
138
+ class ElseNode(ASTNode):
139
+ """Else directive node."""
140
+ children: List[ASTNode] = field(default_factory=list)
141
+
142
+ def __init__(self, children: List[ASTNode] = None,
143
+ line: int = 0, column: int = 0):
144
+ super().__init__(NodeType.ELSE, line, column)
145
+ self.children = children or []
146
+
147
+ def accept(self, visitor):
148
+ return visitor.visit_else(self)
149
+
150
+
151
+ @dataclass(init=False)
152
+ class EventNode(ASTNode):
153
+ """@click event binding node."""
154
+ name: str
155
+ handler: str
156
+
157
+ def __init__(self, name: str, handler: str, line: int = 0, column: int = 0):
158
+ super().__init__(NodeType.EVENT, line, column)
159
+ self.name = name
160
+ self.handler = handler
161
+
162
+ def accept(self, visitor):
163
+ return visitor.visit_event(self)
164
+
165
+
166
+ @dataclass(init=False)
167
+ class BindingNode(ASTNode):
168
+ """:model binding node."""
169
+ name: str
170
+ value: str
171
+
172
+ def __init__(self, name: str, value: str, line: int = 0, column: int = 0):
173
+ super().__init__(NodeType.BINDING, line, column)
174
+ self.name = name
175
+ self.value = value
176
+
177
+ def accept(self, visitor):
178
+ return visitor.visit_binding(self)
179
+
180
+
181
+ @dataclass(init=False)
182
+ class ComponentNode(ASTNode):
183
+ """Custom component node."""
184
+ name: str
185
+ props: Dict[str, str] = field(default_factory=dict)
186
+ children: List[ASTNode] = field(default_factory=list)
187
+ slots: Dict[str, List[ASTNode]] = field(default_factory=dict)
188
+
189
+ def __init__(self, name: str, props: Dict[str, str] = None,
190
+ children: List[ASTNode] = None,
191
+ slots: Dict[str, List[ASTNode]] = None,
192
+ line: int = 0, column: int = 0):
193
+ super().__init__(NodeType.COMPONENT, line, column)
194
+ self.name = name
195
+ self.props = props or {}
196
+ self.children = children or []
197
+ self.slots = slots or {}
198
+
199
+ def accept(self, visitor):
200
+ return visitor.visit_component(self)
201
+
202
+
203
+ @dataclass(init=False)
204
+ class SlotNode(ASTNode):
205
+ """Slot node."""
206
+ name: str = "default"
207
+ children: List[ASTNode] = field(default_factory=list)
208
+
209
+ def __init__(self, name: str = "default", children: List[ASTNode] = None,
210
+ line: int = 0, column: int = 0):
211
+ super().__init__(NodeType.SLOT, line, column)
212
+ self.name = name
213
+ self.children = children or []
214
+
215
+ def accept(self, visitor):
216
+ return visitor.visit_slot(self)
217
+
218
+
219
+ @dataclass(init=False)
220
+ class FragmentNode(ASTNode):
221
+ """Fragment node (multiple root elements)."""
222
+ children: List[ASTNode] = field(default_factory=list)
223
+
224
+ def __init__(self, children: List[ASTNode] = None,
225
+ line: int = 0, column: int = 0):
226
+ super().__init__(NodeType.FRAGMENT, line, column)
227
+ self.children = children or []
228
+
229
+ def accept(self, visitor):
230
+ return visitor.visit_fragment(self)
231
+
232
+
233
+ @dataclass(init=False)
234
+ class AttributeNode(ASTNode):
235
+ """HTML attribute node."""
236
+ name: str
237
+ value: str
238
+
239
+ def __init__(self, name: str, value: str, line: int = 0, column: int = 0):
240
+ super().__init__(NodeType.ATTRIBUTE, line, column)
241
+ self.name = name
242
+ self.value = value
243
+
244
+ def accept(self, visitor):
245
+ return visitor.visit_attribute(self)
246
+
247
+
248
+ @dataclass(init=False)
249
+ class CommentNode(ASTNode):
250
+ """HTML comment node."""
251
+ value: str
252
+
253
+ def __init__(self, value: str, line: int = 0, column: int = 0):
254
+ super().__init__(NodeType.COMMENT, line, column)
255
+ self.value = value
256
+
257
+ def accept(self, visitor):
258
+ return visitor.visit_comment(self)
259
+
260
+
261
+ @dataclass(init=False)
262
+ class DoctypeNode(ASTNode):
263
+ """DOCTYPE node."""
264
+ value: str
265
+
266
+ def __init__(self, value: str, line: int = 0, column: int = 0):
267
+ super().__init__(NodeType.DOCTYPE, line, column)
268
+ self.value = value
269
+
270
+ def accept(self, visitor):
271
+ return visitor.visit_doctype(self)