tw-framework 0.2.3__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 (51) hide show
  1. tw_framework/__init__.py +13 -0
  2. tw_framework/advanced_diagnostics.py +25 -0
  3. tw_framework/asset_optimizer.py +30 -0
  4. tw_framework/ast_nodes.py +283 -0
  5. tw_framework/build.py +7 -0
  6. tw_framework/build_performance.py +26 -0
  7. tw_framework/build_report.py +84 -0
  8. tw_framework/cli.py +1258 -0
  9. tw_framework/code_splitting.py +76 -0
  10. tw_framework/common.py +22 -0
  11. tw_framework/compiler.py +4817 -0
  12. tw_framework/compiler_stats.py +51 -0
  13. tw_framework/dead_code.py +44 -0
  14. tw_framework/dependency_graph.py +91 -0
  15. tw_framework/deploy.py +7 -0
  16. tw_framework/dev.py +9 -0
  17. tw_framework/diagnostics.py +98 -0
  18. tw_framework/dynamic_imports.py +51 -0
  19. tw_framework/error_formatter.py +53 -0
  20. tw_framework/framework.py +3216 -0
  21. tw_framework/hydration.py +129 -0
  22. tw_framework/incremental_cache.py +53 -0
  23. tw_framework/interpreter.py +42 -0
  24. tw_framework/ir.py +171 -0
  25. tw_framework/lexer.py +52 -0
  26. tw_framework/lowering.py +68 -0
  27. tw_framework/parser.py +167 -0
  28. tw_framework/partial_rebuild.py +24 -0
  29. tw_framework/performance_analyzer.py +37 -0
  30. tw_framework/plugin_runtime.py +196 -0
  31. tw_framework/production_optimizer.py +82 -0
  32. tw_framework/reactivity.py +349 -0
  33. tw_framework/render_css.py +22 -0
  34. tw_framework/render_html.py +259 -0
  35. tw_framework/route_optimizer.py +40 -0
  36. tw_framework/router.py +7 -0
  37. tw_framework/runtime_model.py +23 -0
  38. tw_framework/runtime_values.py +31 -0
  39. tw_framework/semantic.py +162 -0
  40. tw_framework/server.py +532 -0
  41. tw_framework/signature.py +51 -0
  42. tw_framework/static_dynamic_auto.py +32 -0
  43. tw_framework/streaming.py +135 -0
  44. tw_framework/test_build_cli_pytest.py +1078 -0
  45. tw_framework/tree_shaking.py +48 -0
  46. tw_framework/twm_parser.py +274 -0
  47. tw_framework-0.2.3.dist-info/METADATA +8 -0
  48. tw_framework-0.2.3.dist-info/RECORD +51 -0
  49. tw_framework-0.2.3.dist-info/WHEEL +5 -0
  50. tw_framework-0.2.3.dist-info/entry_points.txt +2 -0
  51. tw_framework-0.2.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,13 @@
1
+ """TW Framework package."""
2
+
3
+ __version__ = "0.4.0"
4
+
5
+ from .server import run_production_server, SSRCache # noqa: F401
6
+ from .reactivity import ( # noqa: F401
7
+ has_reactivity,
8
+ parse_state_block,
9
+ get_reactivity_runtime_js,
10
+ transform_reactive_attrs,
11
+ )
12
+ from .compiler import compile_file_pipeline, compile_text_pipeline # noqa: F401
13
+ from .interpreter import Interpreter # noqa: F401
@@ -0,0 +1,25 @@
1
+ """
2
+ Advanced compiler diagnostics for TW Framework.
3
+
4
+ Detects duplicate attributes, unused variables, circular imports,
5
+ recursive components, invalid nesting, duplicate IDs, duplicate routes,
6
+ and missing exports.
7
+ """
8
+
9
+ import logging
10
+ from typing import Dict, List
11
+
12
+ from . import compiler
13
+ from .diagnostics import Diagnostic, DiagnosticBag
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ def run_advanced_diagnostics(project_root: str) -> DiagnosticBag:
19
+ """Run all advanced diagnostics and return the results."""
20
+ bag = DiagnosticBag()
21
+ # TODO: Implement actual detection logic
22
+ return bag
23
+
24
+
25
+ __all__ = ["run_advanced_diagnostics"]
@@ -0,0 +1,30 @@
1
+ """
2
+ Smart asset optimization for TW Framework.
3
+
4
+ Automatically compresses images, converts to WebP, lazy loads images,
5
+ preloads critical assets, and removes duplicate CSS/JS.
6
+ """
7
+
8
+ import logging
9
+ import os
10
+ from typing import Dict, List, Optional
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ def optimize_assets(project_root: str, output_dir: str) -> Dict[str, List[str]]:
16
+ """Optimize assets in the output directory."""
17
+ optimized = {
18
+ "images_compressed": [],
19
+ "images_converted_to_webp": [],
20
+ "images_lazy_loaded": [],
21
+ "critical_assets_preloaded": [],
22
+ "duplicate_css_removed": [],
23
+ "duplicate_js_removed": [],
24
+ }
25
+
26
+ # TODO: Implement actual optimization logic
27
+ return optimized
28
+
29
+
30
+ __all__ = ["optimize_assets"]
@@ -0,0 +1,283 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import asdict, dataclass, field, is_dataclass
4
+ from typing import Any, Dict, List, Optional
5
+
6
+
7
+ @dataclass
8
+ class Attribute:
9
+ name: str
10
+ value: Any
11
+
12
+
13
+ def attribute_to_dict(attribute: Any) -> Dict[str, Any]:
14
+ if isinstance(attribute, Attribute):
15
+ return {
16
+ "name": attribute.name,
17
+ "value": serialize_value(attribute.value),
18
+ }
19
+ return {
20
+ "name": getattr(attribute, "name", ""),
21
+ "value": serialize_value(getattr(attribute, "value", None)),
22
+ }
23
+
24
+
25
+ def serialize_value(value: Any) -> Any:
26
+ if value is None or isinstance(value, (str, int, float, bool)):
27
+ return value
28
+ if isinstance(value, Attribute):
29
+ return attribute_to_dict(value)
30
+ if isinstance(value, dict):
31
+ return {str(key): serialize_value(item) for key, item in value.items()}
32
+ if isinstance(value, (list, tuple, set)):
33
+ return [serialize_value(item) for item in value]
34
+ if is_dataclass(value):
35
+ return serialize_value(asdict(value))
36
+ if hasattr(value, "to_dict") and callable(value.to_dict):
37
+ try:
38
+ return serialize_value(value.to_dict())
39
+ except Exception:
40
+ pass
41
+ if hasattr(value, "rules") and isinstance(getattr(value, "rules"), list):
42
+ return {
43
+ "kind": value.__class__.__name__,
44
+ "rules": [serialize_value(rule) for rule in getattr(value, "rules", [])],
45
+ }
46
+ if hasattr(value, "selector") and hasattr(value, "declarations"):
47
+ return {
48
+ "kind": value.__class__.__name__,
49
+ "selector": getattr(value, "selector", ""),
50
+ "declarations": [serialize_value(item) for item in getattr(value, "declarations", [])],
51
+ "children": [serialize_value(item) for item in getattr(value, "children", [])],
52
+ }
53
+ if hasattr(value, "__dict__"):
54
+ raw = {}
55
+ for key, item in vars(value).items():
56
+ if key.startswith("_"):
57
+ continue
58
+ raw[key] = serialize_value(item)
59
+ if raw:
60
+ raw.setdefault("kind", value.__class__.__name__)
61
+ return raw
62
+ return repr(value)
63
+
64
+
65
+ @dataclass
66
+ class HeadModel:
67
+ metas: List[Dict[str, Any]] = field(default_factory=list)
68
+ icon: Optional[str] = None
69
+ seo: Dict[str, Any] = field(default_factory=dict)
70
+
71
+
72
+ @dataclass
73
+ class PageMeta:
74
+ title: str = ""
75
+ layout: Optional[str] = None
76
+ layouts: List[str] = field(default_factory=list)
77
+ render_mode: str = "static"
78
+ revalidate: Optional[int] = None
79
+ redirect_to: Optional[str] = None
80
+ rewrite_to: Optional[str] = None
81
+ responsive: bool = False
82
+
83
+
84
+ @dataclass
85
+ class BaseNode:
86
+ kind: str
87
+
88
+
89
+ @dataclass
90
+ class TextNode(BaseNode):
91
+ value: str
92
+
93
+ def __init__(self, value: str):
94
+ super().__init__("text")
95
+ self.value = value
96
+
97
+
98
+ @dataclass
99
+ class LetNode(BaseNode):
100
+ name: str
101
+ value: Any
102
+
103
+ def __init__(self, name: str, value: Any):
104
+ super().__init__("let")
105
+ self.name = name
106
+ self.value = value
107
+
108
+
109
+ @dataclass
110
+ class IfNode(BaseNode):
111
+ condition: str
112
+ children: List[BaseNode] = field(default_factory=list)
113
+ else_children: List[BaseNode] = field(default_factory=list)
114
+
115
+ def __init__(self, condition: str, children: Optional[List[BaseNode]] = None, else_children: Optional[List[BaseNode]] = None):
116
+ super().__init__("if")
117
+ self.condition = condition
118
+ self.children = children or []
119
+ self.else_children = else_children or []
120
+
121
+
122
+ @dataclass
123
+ class ForNode(BaseNode):
124
+ var_name: str
125
+ iterable: str
126
+ children: List[BaseNode] = field(default_factory=list)
127
+
128
+ def __init__(self, var_name: str, iterable: str, children: Optional[List[BaseNode]] = None):
129
+ super().__init__("for")
130
+ self.var_name = var_name
131
+ self.iterable = iterable
132
+ self.children = children or []
133
+
134
+
135
+ @dataclass
136
+ class ScriptNode(BaseNode):
137
+ raw_js: str
138
+
139
+ def __init__(self, raw_js: str):
140
+ super().__init__("script")
141
+ self.raw_js = raw_js
142
+
143
+
144
+ @dataclass
145
+ class ElementNode(BaseNode):
146
+ tag: str
147
+ text: Optional[str] = None
148
+ attrs: List[Attribute] = field(default_factory=list)
149
+ styles: List[Attribute] = field(default_factory=list)
150
+ events: List[Attribute] = field(default_factory=list)
151
+ router: Dict[str, Any] = field(default_factory=dict)
152
+ children: List[BaseNode] = field(default_factory=list)
153
+
154
+ def __init__(
155
+ self,
156
+ tag: str,
157
+ text: Optional[str] = None,
158
+ attrs: Optional[List[Attribute]] = None,
159
+ styles: Optional[List[Attribute]] = None,
160
+ events: Optional[List[Attribute]] = None,
161
+ router: Optional[Dict[str, Any]] = None,
162
+ children: Optional[List[BaseNode]] = None,
163
+ ):
164
+ super().__init__("element")
165
+ self.tag = tag
166
+ self.text = text
167
+ self.attrs = attrs or []
168
+ self.styles = styles or []
169
+ self.events = events or []
170
+ self.router = router or {}
171
+ self.children = children or []
172
+
173
+
174
+ @dataclass
175
+ class ComponentNode(BaseNode):
176
+ name: str
177
+ props: List[Attribute] = field(default_factory=list)
178
+ children: List[BaseNode] = field(default_factory=list)
179
+
180
+ def __init__(self, name: str, props: Optional[List[Attribute]] = None, children: Optional[List[BaseNode]] = None):
181
+ super().__init__("component")
182
+ self.name = name
183
+ self.props = props or []
184
+ self.children = children or []
185
+
186
+
187
+ @dataclass
188
+ class Program:
189
+ meta: PageMeta = field(default_factory=PageMeta)
190
+ head: HeadModel = field(default_factory=HeadModel)
191
+ lets: Dict[str, Any] = field(default_factory=dict)
192
+ state: Dict[str, Any] = field(default_factory=dict)
193
+ body: List[BaseNode] = field(default_factory=list)
194
+ loaded_sheets: List[Any] = field(default_factory=list)
195
+ loaded_json: List[Dict[str, Any]] = field(default_factory=list)
196
+ source_path: str = ""
197
+ legacy_page: Any = None
198
+
199
+ def to_dict(self) -> Dict[str, Any]:
200
+ return {
201
+ "meta": {
202
+ "title": self.meta.title,
203
+ "layout": self.meta.layout,
204
+ "layouts": list(self.meta.layouts),
205
+ "render_mode": self.meta.render_mode,
206
+ "revalidate": self.meta.revalidate,
207
+ "redirect_to": self.meta.redirect_to,
208
+ "rewrite_to": self.meta.rewrite_to,
209
+ "responsive": self.meta.responsive,
210
+ },
211
+ "head": {
212
+ "metas": list(self.head.metas),
213
+ "icon": self.head.icon,
214
+ "seo": dict(self.head.seo),
215
+ },
216
+ "lets": serialize_value(self.lets),
217
+ "state": serialize_value(self.state),
218
+ "body": [node_to_dict(node) for node in self.body],
219
+ "loaded_sheets": serialize_value(self.loaded_sheets),
220
+ "loaded_json": serialize_value(self.loaded_json),
221
+ "source_path": self.source_path,
222
+ }
223
+
224
+
225
+ def node_to_dict(node: BaseNode) -> Dict[str, Any]:
226
+ if isinstance(node, TextNode):
227
+ return {"kind": node.kind, "value": node.value}
228
+ if isinstance(node, LetNode):
229
+ return {"kind": node.kind, "name": node.name, "value": serialize_value(node.value)}
230
+ if isinstance(node, IfNode):
231
+ return {
232
+ "kind": node.kind,
233
+ "condition": node.condition,
234
+ "children": [node_to_dict(child) for child in node.children],
235
+ "else_children": [node_to_dict(child) for child in node.else_children],
236
+ }
237
+ if isinstance(node, ForNode):
238
+ return {
239
+ "kind": node.kind,
240
+ "var_name": node.var_name,
241
+ "iterable": node.iterable,
242
+ "children": [node_to_dict(child) for child in node.children],
243
+ }
244
+ if isinstance(node, ScriptNode):
245
+ return {"kind": node.kind, "raw_js": node.raw_js}
246
+ if isinstance(node, ElementNode):
247
+ return {
248
+ "kind": node.kind,
249
+ "tag": node.tag,
250
+ "text": node.text,
251
+ "attrs": [attribute_to_dict(attr) for attr in node.attrs],
252
+ "styles": [attribute_to_dict(attr) for attr in node.styles],
253
+ "events": [attribute_to_dict(attr) for attr in node.events],
254
+ "router": serialize_value(node.router),
255
+ "children": [node_to_dict(child) for child in node.children],
256
+ }
257
+ if isinstance(node, ComponentNode):
258
+ return {
259
+ "kind": node.kind,
260
+ "name": node.name,
261
+ "props": [attribute_to_dict(prop) for prop in node.props],
262
+ "children": [node_to_dict(child) for child in node.children],
263
+ }
264
+ return {"kind": getattr(node, "kind", "unknown"), "repr": repr(node)}
265
+
266
+
267
+ __all__ = [
268
+ "Attribute",
269
+ "BaseNode",
270
+ "ComponentNode",
271
+ "ElementNode",
272
+ "ForNode",
273
+ "HeadModel",
274
+ "IfNode",
275
+ "LetNode",
276
+ "PageMeta",
277
+ "Program",
278
+ "ScriptNode",
279
+ "TextNode",
280
+ "attribute_to_dict",
281
+ "node_to_dict",
282
+ "serialize_value",
283
+ ]
tw_framework/build.py ADDED
@@ -0,0 +1,7 @@
1
+ from .framework import ( # noqa: F401
2
+ BuildSummary,
3
+ build_hidden_site,
4
+ clean_project_outputs,
5
+ doctor_project,
6
+ inspect_project,
7
+ )
@@ -0,0 +1,26 @@
1
+ """
2
+ Build performance optimization for TW Framework.
3
+
4
+ Parallelizes compilation, uses multiple CPU cores, and avoids recompiling unchanged files.
5
+ """
6
+
7
+ import logging
8
+ import os
9
+ from typing import List, Optional
10
+
11
+ from . import compiler
12
+ from .compiler_stats import CompilerStats
13
+ from .incremental_cache import IncrementalCache
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ def optimize_build(project_root: str, output_dir: str, force: bool = False, workers: Optional[int] = None) -> CompilerStats:
19
+ """Run an optimized build with parallelism and caching."""
20
+ stats = CompilerStats()
21
+ cache = IncrementalCache(project_root)
22
+ # TODO: Implement actual parallel build logic
23
+ return stats
24
+
25
+
26
+ __all__ = ["optimize_build"]
@@ -0,0 +1,84 @@
1
+ """
2
+ Build report generation for TW Framework.
3
+
4
+ Generates .tw/build-report.json with bundle sizes, timings, and analysis.
5
+ """
6
+
7
+ import json
8
+ import logging
9
+ import os
10
+ import time
11
+ from typing import Any, Dict, List, Optional
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class BuildReport:
17
+ """Collects build metrics and generates a report."""
18
+
19
+ def __init__(self, project_root: str):
20
+ self.project_root = project_root
21
+ self.start_time = time.time()
22
+ self.pages: List[Dict[str, Any]] = []
23
+ self.components: List[Dict[str, Any]] = []
24
+ self.total_bundle_size = 0
25
+ self.total_css_size = 0
26
+ self.total_js_size = 0
27
+ self.total_image_size = 0
28
+ self.unused_code: List[str] = []
29
+ self.largest_components: List[Dict[str, Any]] = []
30
+ self.slowest_pages: List[Dict[str, Any]] = []
31
+ self.build_timings: Dict[str, float] = {}
32
+
33
+ def add_page(self, path: str, size: int, duration: float):
34
+ self.pages.append({"path": path, "size": size, "duration": duration})
35
+ self.total_bundle_size += size
36
+
37
+ def add_component(self, name: str, size: int):
38
+ self.components.append({"name": name, "size": size})
39
+ self.total_bundle_size += size
40
+
41
+ def add_css_size(self, size: int):
42
+ self.total_css_size += size
43
+
44
+ def add_js_size(self, size: int):
45
+ self.total_js_size += size
46
+
47
+ def add_image_size(self, size: int):
48
+ self.total_image_size += size
49
+
50
+ def add_unused_code(self, item: str):
51
+ self.unused_code.append(item)
52
+
53
+ def finalize(self) -> Dict[str, Any]:
54
+ duration = time.time() - self.start_time
55
+ self.pages.sort(key=lambda p: p["duration"], reverse=True)
56
+ self.slowest_pages = self.pages[:10]
57
+ self.components.sort(key=lambda c: c["size"], reverse=True)
58
+ self.largest_components = self.components[:10]
59
+ return {
60
+ "build_duration_seconds": round(duration, 2),
61
+ "total_bundle_size_bytes": self.total_bundle_size,
62
+ "total_css_size_bytes": self.total_css_size,
63
+ "total_js_size_bytes": self.total_js_size,
64
+ "total_image_size_bytes": self.total_image_size,
65
+ "pages_compiled": len(self.pages),
66
+ "components_compiled": len(self.components),
67
+ "unused_code": self.unused_code,
68
+ "largest_components": self.largest_components,
69
+ "slowest_pages": self.slowest_pages,
70
+ "build_timings": self.build_timings,
71
+ }
72
+
73
+ def save(self):
74
+ report = self.finalize()
75
+ report_dir = os.path.join(self.project_root, ".tw")
76
+ os.makedirs(report_dir, exist_ok=True)
77
+ report_path = os.path.join(report_dir, "build-report.json")
78
+ with open(report_path, "w", encoding="utf-8") as f:
79
+ json.dump(report, f, indent=2)
80
+ logger.info("Build report saved to %s", report_path)
81
+ return report
82
+
83
+
84
+ __all__ = ["BuildReport"]