pywire 0.1.0__py3-none-any.whl → 0.1.1__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 (101) hide show
  1. {pywire-0.1.0.dist-info → pywire-0.1.1.dist-info}/METADATA +23 -1
  2. pywire-0.1.1.dist-info/RECORD +9 -0
  3. pywire/__init__.py +0 -2
  4. pywire/cli/__init__.py +0 -1
  5. pywire/cli/generators.py +0 -48
  6. pywire/cli/main.py +0 -309
  7. pywire/cli/tui.py +0 -563
  8. pywire/cli/validate.py +0 -26
  9. pywire/client/.prettierignore +0 -8
  10. pywire/client/.prettierrc +0 -7
  11. pywire/client/build.mjs +0 -73
  12. pywire/client/eslint.config.js +0 -46
  13. pywire/client/package.json +0 -39
  14. pywire/client/pnpm-lock.yaml +0 -2971
  15. pywire/client/src/core/app.ts +0 -263
  16. pywire/client/src/core/dom-updater.test.ts +0 -78
  17. pywire/client/src/core/dom-updater.ts +0 -321
  18. pywire/client/src/core/index.ts +0 -5
  19. pywire/client/src/core/transport-manager.test.ts +0 -179
  20. pywire/client/src/core/transport-manager.ts +0 -159
  21. pywire/client/src/core/transports/base.ts +0 -122
  22. pywire/client/src/core/transports/http.ts +0 -142
  23. pywire/client/src/core/transports/index.ts +0 -13
  24. pywire/client/src/core/transports/websocket.ts +0 -97
  25. pywire/client/src/core/transports/webtransport.ts +0 -149
  26. pywire/client/src/dev/dev-app.ts +0 -93
  27. pywire/client/src/dev/error-trace.test.ts +0 -97
  28. pywire/client/src/dev/error-trace.ts +0 -76
  29. pywire/client/src/dev/index.ts +0 -4
  30. pywire/client/src/dev/status-overlay.ts +0 -63
  31. pywire/client/src/events/handler.test.ts +0 -318
  32. pywire/client/src/events/handler.ts +0 -454
  33. pywire/client/src/pywire.core.ts +0 -22
  34. pywire/client/src/pywire.dev.ts +0 -27
  35. pywire/client/tsconfig.json +0 -17
  36. pywire/client/vitest.config.ts +0 -15
  37. pywire/compiler/__init__.py +0 -6
  38. pywire/compiler/ast_nodes.py +0 -304
  39. pywire/compiler/attributes/__init__.py +0 -6
  40. pywire/compiler/attributes/base.py +0 -24
  41. pywire/compiler/attributes/conditional.py +0 -37
  42. pywire/compiler/attributes/events.py +0 -55
  43. pywire/compiler/attributes/form.py +0 -37
  44. pywire/compiler/attributes/loop.py +0 -75
  45. pywire/compiler/attributes/reactive.py +0 -34
  46. pywire/compiler/build.py +0 -28
  47. pywire/compiler/build_artifacts.py +0 -342
  48. pywire/compiler/codegen/__init__.py +0 -5
  49. pywire/compiler/codegen/attributes/__init__.py +0 -6
  50. pywire/compiler/codegen/attributes/base.py +0 -19
  51. pywire/compiler/codegen/attributes/events.py +0 -35
  52. pywire/compiler/codegen/directives/__init__.py +0 -6
  53. pywire/compiler/codegen/directives/base.py +0 -16
  54. pywire/compiler/codegen/directives/path.py +0 -53
  55. pywire/compiler/codegen/generator.py +0 -2341
  56. pywire/compiler/codegen/template.py +0 -2178
  57. pywire/compiler/directives/__init__.py +0 -7
  58. pywire/compiler/directives/base.py +0 -20
  59. pywire/compiler/directives/component.py +0 -33
  60. pywire/compiler/directives/context.py +0 -93
  61. pywire/compiler/directives/layout.py +0 -49
  62. pywire/compiler/directives/no_spa.py +0 -24
  63. pywire/compiler/directives/path.py +0 -71
  64. pywire/compiler/directives/props.py +0 -88
  65. pywire/compiler/exceptions.py +0 -19
  66. pywire/compiler/interpolation/__init__.py +0 -6
  67. pywire/compiler/interpolation/base.py +0 -28
  68. pywire/compiler/interpolation/jinja.py +0 -272
  69. pywire/compiler/parser.py +0 -750
  70. pywire/compiler/paths.py +0 -29
  71. pywire/compiler/preprocessor.py +0 -43
  72. pywire/core/wire.py +0 -119
  73. pywire/py.typed +0 -0
  74. pywire/runtime/__init__.py +0 -7
  75. pywire/runtime/aioquic_server.py +0 -194
  76. pywire/runtime/app.py +0 -889
  77. pywire/runtime/compile_error_page.py +0 -195
  78. pywire/runtime/debug.py +0 -203
  79. pywire/runtime/dev_server.py +0 -434
  80. pywire/runtime/dev_server.py.broken +0 -268
  81. pywire/runtime/error_page.py +0 -64
  82. pywire/runtime/error_renderer.py +0 -23
  83. pywire/runtime/escape.py +0 -23
  84. pywire/runtime/files.py +0 -40
  85. pywire/runtime/helpers.py +0 -97
  86. pywire/runtime/http_transport.py +0 -253
  87. pywire/runtime/loader.py +0 -272
  88. pywire/runtime/logging.py +0 -72
  89. pywire/runtime/page.py +0 -384
  90. pywire/runtime/pydantic_integration.py +0 -52
  91. pywire/runtime/router.py +0 -229
  92. pywire/runtime/server.py +0 -25
  93. pywire/runtime/style_collector.py +0 -31
  94. pywire/runtime/upload_manager.py +0 -76
  95. pywire/runtime/validation.py +0 -449
  96. pywire/runtime/websocket.py +0 -665
  97. pywire/runtime/webtransport_handler.py +0 -195
  98. pywire-0.1.0.dist-info/RECORD +0 -104
  99. {pywire-0.1.0.dist-info → pywire-0.1.1.dist-info}/WHEEL +0 -0
  100. {pywire-0.1.0.dist-info → pywire-0.1.1.dist-info}/entry_points.txt +0 -0
  101. {pywire-0.1.0.dist-info → pywire-0.1.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,304 +0,0 @@
1
- """AST node definitions for PyWire compiler."""
2
-
3
- import ast
4
- from dataclasses import dataclass, field
5
- from typing import Dict, List, Optional, Tuple, Union
6
-
7
-
8
- @dataclass
9
- class ASTNode:
10
- """Base for all AST nodes."""
11
-
12
- line: int
13
- column: int
14
-
15
-
16
- @dataclass
17
- class Directive(ASTNode):
18
- """Base for directives."""
19
-
20
- name: str
21
-
22
-
23
- @dataclass
24
- class PathDirective(Directive):
25
- """!path { 'name': '/route/{param}' } or !path '/route'"""
26
-
27
- routes: Dict[str, str] # {'name': '/route/{param}'}
28
- is_simple_string: bool = False
29
-
30
- def __str__(self) -> str:
31
- return f"PathDirective(routes={self.routes}, simple={self.is_simple_string})"
32
-
33
-
34
- @dataclass
35
- class NoSpaDirective(Directive):
36
- """!no_spa - disables client-side SPA navigation for this page."""
37
-
38
- def __str__(self) -> str:
39
- return "NoSpaDirective()"
40
-
41
-
42
- @dataclass
43
- class LayoutDirective(Directive):
44
- """!layout "path/to/layout.pywire" """
45
-
46
- layout_path: str
47
-
48
- def __str__(self) -> str:
49
- return f"LayoutDirective(path={self.layout_path})"
50
-
51
-
52
- @dataclass
53
- class ComponentDirective(Directive):
54
- """!component 'path/to/component' as Name"""
55
-
56
- path: str
57
- component_name: str # PascalCase name (e.g. 'Badge')
58
-
59
- def __str__(self) -> str:
60
- return f"ComponentDirective(name={self.component_name}, path={self.path})"
61
-
62
-
63
- @dataclass
64
- class PropsDirective(Directive):
65
- """!props(name: type, arg=default)"""
66
-
67
- # List of (name, type_hint_str, default_value_str_or_None)
68
- args: List[Tuple[str, str, Optional[str]]]
69
-
70
- def __str__(self) -> str:
71
- return f"PropsDirective(args={self.args})"
72
-
73
-
74
- @dataclass
75
- class InjectDirective(Directive):
76
- """!inject { local: 'GLOBAL' }"""
77
-
78
- mapping: Dict[str, str] # {local_var: global_key}
79
-
80
- def __str__(self) -> str:
81
- return f"InjectDirective(mapping={self.mapping})"
82
-
83
-
84
- @dataclass
85
- class ProvideDirective(Directive):
86
- """!provide { 'GLOBAL': local }"""
87
-
88
- mapping: Dict[str, str] # {global_key: local_var_expr}
89
-
90
- def __str__(self) -> str:
91
- return f"ProvideDirective(mapping={self.mapping})"
92
-
93
-
94
- @dataclass
95
- class SpecialAttribute(ASTNode):
96
- """Base for special attributes ($, @, :)."""
97
-
98
- name: str
99
- value: str
100
-
101
-
102
- @dataclass
103
- class KeyAttribute(SpecialAttribute):
104
- """$key={unique_id}."""
105
-
106
- expr: str
107
-
108
- def __str__(self) -> str:
109
- return f"KeyAttribute(expr={self.expr})"
110
-
111
-
112
- @dataclass
113
- class IfAttribute(SpecialAttribute):
114
- """$if={condition}."""
115
-
116
- condition: str
117
-
118
- def __str__(self) -> str:
119
- return f"IfAttribute(condition={self.condition})"
120
-
121
-
122
- @dataclass
123
- class ShowAttribute(SpecialAttribute):
124
- """$show={condition}."""
125
-
126
- condition: str
127
-
128
- def __str__(self) -> str:
129
- return f"ShowAttribute(condition={self.condition})"
130
-
131
-
132
- @dataclass
133
- class ForAttribute(SpecialAttribute):
134
- """$for={item in items}"."""
135
-
136
- is_template_tag: bool # <template $for>
137
- loop_vars: str # "item" or "key, value"
138
- iterable: str # "items" or "items.items()"
139
- key: Optional[str] = None
140
-
141
- def __str__(self) -> str:
142
- return f"ForAttribute(vars={self.loop_vars}, in={self.iterable})"
143
-
144
-
145
- @dataclass
146
- class FieldValidationRules:
147
- """Validation rules for a single form field."""
148
-
149
- name: str
150
- required: bool = False
151
- required_expr: Optional[str] = None # For required={condition}
152
- pattern: Optional[str] = None
153
- minlength: Optional[int] = None
154
- maxlength: Optional[int] = None
155
- min_value: Optional[str] = None # String to support dates
156
- min_expr: Optional[str] = None # For min={expr}
157
- max_value: Optional[str] = None
158
- max_expr: Optional[str] = None # For max={expr}
159
- step: Optional[str] = None
160
- input_type: str = "text" # email, url, number, date, etc.
161
- title: Optional[str] = None # Custom error message
162
- max_size: Optional[int] = None # Max file size in bytes
163
- allowed_types: Optional[List[str]] = None # Allowed MIME types or extensions
164
-
165
- def __str__(self) -> str:
166
- return f"FieldValidationRules(name={self.name}, required={self.required})"
167
-
168
-
169
- @dataclass
170
- class FormValidationSchema:
171
- """Schema containing all validation rules for a form."""
172
-
173
- fields: Dict[str, FieldValidationRules] = field(default_factory=dict)
174
- model_name: Optional[str] = None # For $model={ClassName}
175
-
176
- def __str__(self) -> str:
177
- return (
178
- f"FormValidationSchema(fields={len(self.fields)}, model={self.model_name})"
179
- )
180
-
181
-
182
- @dataclass
183
- class ModelAttribute(SpecialAttribute):
184
- """$model={ModelClassName} - Pydantic model binding."""
185
-
186
- model_name: str
187
-
188
- def __str__(self) -> str:
189
- return f"ModelAttribute(model={self.model_name})"
190
-
191
-
192
- @dataclass
193
- class EventAttribute(SpecialAttribute):
194
- """@click={handler_name} or @click={handler(arg1)}."""
195
-
196
- event_type: str # 'click', 'submit', etc.
197
- handler_name: str
198
- args: List[str] = field(
199
- default_factory=list
200
- ) # List of python expressions for arguments
201
- modifiers: List[str] = field(
202
- default_factory=list
203
- ) # List of modifiers (e.g. ['prevent', 'stop'])
204
- # Form-specific fields
205
- validation_schema: Optional[FormValidationSchema] = None # Set for @submit handlers
206
-
207
- def __str__(self) -> str:
208
- return (
209
- f"EventAttribute(event={self.event_type}, modifiers={self.modifiers}, "
210
- f"handler={self.handler_name}, args={self.args})"
211
- )
212
-
213
-
214
- @dataclass
215
- class ReactiveAttribute(SpecialAttribute):
216
- """
217
- attr={expression}
218
- Represents a reactive attribute where the value is a python expression.
219
- """
220
-
221
- expr: str
222
-
223
- def __str__(self) -> str:
224
- return f"ReactiveAttribute(name={self.name}, expr={self.expr})"
225
-
226
-
227
- @dataclass
228
- class SpreadAttribute(SpecialAttribute):
229
- """
230
- {**attrs} (preprocessed to __pywire_spread__="{**attrs}")
231
- Represents a spread of attributes.
232
- """
233
-
234
- expr: str
235
-
236
- def __str__(self) -> str:
237
- return f"SpreadAttribute(expr={self.expr})"
238
-
239
-
240
- @dataclass
241
- class InterpolationNode(ASTNode):
242
- """Represents {variable} in text.
243
-
244
- Use {$html expr} syntax for raw/unescaped output.
245
- """
246
-
247
- expression: str # Python expression to evaluate
248
- is_raw: bool = False # If True, output is not HTML-escaped (use {$html expr})
249
-
250
- def __str__(self) -> str:
251
- raw_str = ", raw=True" if self.is_raw else ""
252
- return f"InterpolationNode(expr={self.expression}{raw_str})"
253
-
254
-
255
- @dataclass
256
- class TemplateNode(ASTNode):
257
- """HTML element or text node."""
258
-
259
- tag: Optional[str] # None for text nodes
260
- attributes: Dict[str, str] = field(default_factory=dict) # Regular HTML attributes
261
- special_attributes: List[Union[SpecialAttribute, "InterpolationNode"]] = field(
262
- default_factory=list
263
- )
264
- children: List["TemplateNode"] = field(default_factory=list)
265
- text_content: Optional[str] = None
266
- is_raw: bool = False
267
-
268
- def __str__(self) -> str:
269
- if self.tag:
270
- return (
271
- f"TemplateNode(tag={self.tag}, attrs={len(self.attributes)}, "
272
- f"special={len(self.special_attributes)}, "
273
- f"children={len(self.children)})"
274
- )
275
- return f"TemplateNode(text={self.text_content[:30] if self.text_content else None})"
276
-
277
-
278
- @dataclass
279
- class ParsedPyWire:
280
- """Top-level parsed document."""
281
-
282
- directives: List[Directive] = field(default_factory=list)
283
- template: List[TemplateNode] = field(default_factory=list)
284
- python_code: str = "" # Raw Python section (above ---html---)
285
- python_ast: Optional[ast.Module] = None # Parsed Python AST
286
- file_path: str = ""
287
-
288
- def get_directive_by_type(self, directive_type: type) -> Optional[Directive]:
289
- """Get first directive of specified type."""
290
- for directive in self.directives:
291
- if isinstance(directive, directive_type):
292
- return directive
293
- return None
294
-
295
- def get_directives_by_type(self, directive_type: type) -> List[Directive]:
296
- """Get all directives of specified type."""
297
- return [d for d in self.directives if isinstance(d, directive_type)]
298
-
299
- def __str__(self) -> str:
300
- return (
301
- f"ParsedPyWire(directives={len(self.directives)}, "
302
- f"template_nodes={len(self.template)}, "
303
- f"python_lines={len(self.python_code.splitlines())})"
304
- )
@@ -1,6 +0,0 @@
1
- """Attribute parsers."""
2
-
3
- from pywire.compiler.attributes.base import AttributeParser
4
- from pywire.compiler.attributes.events import EventAttributeParser
5
-
6
- __all__ = ["AttributeParser", "EventAttributeParser"]
@@ -1,24 +0,0 @@
1
- """Base attribute parser."""
2
-
3
- from abc import ABC, abstractmethod
4
- from typing import Optional
5
-
6
- from pywire.compiler.ast_nodes import SpecialAttribute
7
-
8
-
9
- class AttributeParser(ABC):
10
- """Base class for parsing special attributes - extensible for $, @, : types."""
11
-
12
- PREFIX: str # '@', '$', or ':'
13
-
14
- @abstractmethod
15
- def can_parse(self, attr_name: str) -> bool:
16
- """Check if this parser can handle the attribute."""
17
- return attr_name.startswith(self.PREFIX)
18
-
19
- @abstractmethod
20
- def parse(
21
- self, attr_name: str, attr_value: str, line: int, col: int
22
- ) -> Optional[SpecialAttribute]:
23
- """Parse attribute. Returns None if not applicable."""
24
- pass
@@ -1,37 +0,0 @@
1
- """Conditional attribute parsers ($if, $show)."""
2
-
3
- from typing import Optional
4
-
5
- from pywire.compiler.ast_nodes import IfAttribute, ShowAttribute, SpecialAttribute
6
- from pywire.compiler.attributes.base import AttributeParser
7
- from pywire.compiler.exceptions import PyWireSyntaxError
8
-
9
-
10
- class ConditionalAttributeParser(AttributeParser):
11
- """Parses $if and $show attributes."""
12
-
13
- def can_parse(self, attr_name: str) -> bool:
14
- """Check if attribute is $if or $show."""
15
- return attr_name in ("$if", "$show")
16
-
17
- def parse(
18
- self, attr_name: str, attr_value: str, line: int, col: int
19
- ) -> Optional[SpecialAttribute]:
20
- """Parse conditional attribute."""
21
- if not (attr_value.startswith("{") and attr_value.endswith("}")):
22
- raise PyWireSyntaxError(
23
- f"Value for '{attr_name}' must be wrapped in brackets: {attr_name}={{expr}}",
24
- line=line,
25
- )
26
-
27
- expr = attr_value[1:-1].strip()
28
-
29
- if attr_name == "$if":
30
- return IfAttribute(
31
- name=attr_name, value=attr_value, condition=expr, line=line, column=col
32
- )
33
- elif attr_name == "$show":
34
- return ShowAttribute(
35
- name=attr_name, value=attr_value, condition=expr, line=line, column=col
36
- )
37
- return None
@@ -1,55 +0,0 @@
1
- """Event attribute parser."""
2
-
3
- import re
4
- from typing import List, Optional
5
-
6
- from pywire.compiler.ast_nodes import EventAttribute
7
- from pywire.compiler.attributes.base import AttributeParser
8
- from pywire.compiler.exceptions import PyWireSyntaxError
9
-
10
-
11
- class EventAttributeParser(AttributeParser):
12
- """Parses @event attributes (click, submit, etc.)."""
13
-
14
- PREFIX = "@"
15
- PATTERN = re.compile(r"^@(\w+)$")
16
-
17
- def can_parse(self, attr_name: str) -> bool:
18
- """Check if attribute starts with @."""
19
- return attr_name.startswith(self.PREFIX)
20
-
21
- def parse(
22
- self, attr_name: str, attr_value: str, line: int, col: int
23
- ) -> Optional[EventAttribute]:
24
- """Parse @click.prevent.stop={handler_name} attribute."""
25
- # Remove @ prefix
26
- full_event = attr_name[1:]
27
- parts = full_event.split(".")
28
- event_type = parts[0]
29
- modifiers = [m for m in parts[1:] if m]
30
-
31
- if not (attr_value.startswith("{") and attr_value.endswith("}")):
32
- raise PyWireSyntaxError(
33
- f"Event handler for '{attr_name}' must be wrapped in brackets: "
34
- f"{attr_name}={{expr}}",
35
- line=line,
36
- )
37
-
38
- handler_name = attr_value[1:-1].strip() # Strip brackets and whitespace
39
-
40
- # Parse handler args if present (future: handler(arg1, arg2))
41
- handler_args: List[str] = []
42
- if "(" in handler_name:
43
- # Future: parse args
44
- pass
45
-
46
- return EventAttribute(
47
- name=attr_name,
48
- value=attr_value,
49
- event_type=event_type,
50
- handler_name=handler_name,
51
- modifiers=modifiers,
52
- args=handler_args,
53
- line=line,
54
- column=col,
55
- )
@@ -1,37 +0,0 @@
1
- """Form attribute parsers for $model and $field."""
2
-
3
- from typing import Optional
4
-
5
- from pywire.compiler.ast_nodes import ModelAttribute
6
- from pywire.compiler.attributes.base import AttributeParser
7
-
8
-
9
- class ModelAttributeParser(AttributeParser):
10
- """Parses $model={ModelClassName} attribute for Pydantic binding."""
11
-
12
- PREFIX = "$model"
13
-
14
- def can_parse(self, attr_name: str) -> bool:
15
- """Check if attribute is $model."""
16
- return attr_name == "$model"
17
-
18
- def parse(
19
- self, attr_name: str, attr_value: str, line: int, col: int
20
- ) -> Optional[ModelAttribute]:
21
- """Parse $model={ClassName} attribute."""
22
- if attr_name != "$model":
23
- return None
24
-
25
- model_name = attr_value.strip().strip("\"'")
26
- if model_name.startswith("{") and model_name.endswith("}"):
27
- model_name = model_name[1:-1].strip()
28
- if not model_name:
29
- return None
30
-
31
- return ModelAttribute(
32
- name=attr_name,
33
- value=attr_value,
34
- model_name=model_name,
35
- line=line,
36
- column=col,
37
- )
@@ -1,75 +0,0 @@
1
- """Loop attribute parsers ($for, $key)."""
2
-
3
- from typing import Optional
4
-
5
- from pywire.compiler.ast_nodes import ForAttribute, KeyAttribute, SpecialAttribute
6
- from pywire.compiler.attributes.base import AttributeParser
7
- from pywire.compiler.exceptions import PyWireSyntaxError
8
-
9
-
10
- class LoopAttributeParser(AttributeParser):
11
- """Parses $for attributes."""
12
-
13
- def can_parse(self, attr_name: str) -> bool:
14
- """Check if attribute is $for."""
15
- return attr_name == "$for"
16
-
17
- def parse(
18
- self, attr_name: str, attr_value: str, line: int, col: int
19
- ) -> Optional[SpecialAttribute]:
20
- """Parse $for attribute."""
21
- if not (attr_value.startswith("{") and attr_value.endswith("}")):
22
- raise PyWireSyntaxError(
23
- f"Value for '{attr_name}' must be wrapped in brackets: "
24
- f"{attr_name}={{item in items}}",
25
- line=line,
26
- )
27
-
28
- expr = attr_value[1:-1].strip()
29
- # Parse "item in items" or "key, value in items"
30
- parts = expr.split(" in ", 1)
31
- if len(parts) != 2:
32
- # We don't raise error here, just return nothing or let it be
33
- # handled as valid attribute?
34
- # Ideally validation happens here.
35
- # But creating AST node blindly is safer if we want to defer errors.
36
- # But "item in items" is pretty fundamental.
37
- raise ValueError(
38
- f"Invalid $for syntax at line {line}: '{attr_value}'. Expected 'item in items'."
39
- )
40
-
41
- loop_vars = parts[0].strip()
42
- iterable = parts[1].strip()
43
-
44
- return ForAttribute(
45
- name=attr_name,
46
- value=attr_value,
47
- is_template_tag=False, # Populated later
48
- loop_vars=loop_vars,
49
- iterable=iterable,
50
- line=line,
51
- column=col,
52
- )
53
-
54
-
55
- class KeyAttributeParser(AttributeParser):
56
- """Parses $key attributes."""
57
-
58
- def can_parse(self, attr_name: str) -> bool:
59
- """Check if attribute is $key."""
60
- return attr_name == "$key"
61
-
62
- def parse(
63
- self, attr_name: str, attr_value: str, line: int, col: int
64
- ) -> Optional[SpecialAttribute]:
65
- """Parse $key attribute."""
66
- if not (attr_value.startswith("{") and attr_value.endswith("}")):
67
- raise PyWireSyntaxError(
68
- f"Value for '{attr_name}' must be wrapped in brackets: {attr_name}={{expr}}",
69
- line=line,
70
- )
71
-
72
- expr = attr_value[1:-1].strip()
73
- return KeyAttribute(
74
- name=attr_name, value=attr_value, expr=expr, line=line, column=col
75
- )
@@ -1,34 +0,0 @@
1
- """Reactive attribute parser (:attr)."""
2
-
3
- from typing import Optional
4
-
5
- from pywire.compiler.ast_nodes import ReactiveAttribute, SpecialAttribute
6
- from pywire.compiler.attributes.base import AttributeParser
7
-
8
-
9
- class ReactiveAttributeParser(AttributeParser):
10
- """Parses reactive attributes starting with :"""
11
-
12
- def can_parse(self, attr_name: str) -> bool:
13
- """
14
- Check if attribute starts with : but is NOT a directive like :class (if we had those)
15
- or other special chars.
16
- Actually requirements say: ":attribute"
17
- "it explicitly does NOT support framework attributes like anything starting with @ or $"
18
- But @ and $ are handled by other parsers anyway.
19
- So we just check for starting with :
20
- """
21
- # Disabled: :prop="val" syntax is deprecated.
22
- # Reactive attributes must use prop={expr} syntax which is handled by parser fallback.
23
- return False
24
-
25
- def parse(
26
- self, attr_name: str, attr_value: str, line: int, col: int
27
- ) -> Optional[SpecialAttribute]:
28
- """Parse attr={expr}"."""
29
- # Strip the leading :
30
- real_name = attr_name[1:]
31
-
32
- return ReactiveAttribute(
33
- name=real_name, value=attr_value, expr=attr_value, line=line, column=col
34
- )
pywire/compiler/build.py DELETED
@@ -1,28 +0,0 @@
1
- """Build system for production."""
2
-
3
- from __future__ import annotations
4
-
5
- from pathlib import Path
6
- from typing import TYPE_CHECKING, Optional
7
-
8
- if TYPE_CHECKING:
9
- from pywire.compiler.build_artifacts import BuildSummary
10
-
11
-
12
- def build_project(
13
- optimize: bool = False,
14
- pages_dir: Optional[Path] = None,
15
- out_dir: Optional[Path] = None,
16
- ) -> BuildSummary:
17
- """Build project for production."""
18
- if pages_dir is None:
19
- pages_dir = Path("pages")
20
-
21
- from pywire.cli.validate import validate_project
22
- from pywire.compiler.build_artifacts import build_artifacts
23
-
24
- errors = validate_project(pages_dir=pages_dir)
25
- if errors:
26
- raise ValueError(f"Build failed with {len(errors)} errors")
27
-
28
- return build_artifacts(pages_dir=pages_dir, out_dir=out_dir, optimize=optimize)