quantum-framework 0.18.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 (333) hide show
  1. quantum/__init__.py +1 -0
  2. quantum/cli/__init__.py +2 -0
  3. quantum/cli/admin.py +131 -0
  4. quantum/cli/check.py +223 -0
  5. quantum/cli/commands/__init__.py +15 -0
  6. quantum/cli/commands/build.py +414 -0
  7. quantum/cli/commands/dev.py +185 -0
  8. quantum/cli/commands/docs.py +329 -0
  9. quantum/cli/commands/lint.py +523 -0
  10. quantum/cli/commands/migrate.py +548 -0
  11. quantum/cli/commands/new.py +622 -0
  12. quantum/cli/commands/serve.py +190 -0
  13. quantum/cli/commands/test.py +193 -0
  14. quantum/cli/deploy.py +810 -0
  15. quantum/cli/hot_reload.py +951 -0
  16. quantum/cli/jobs.py +356 -0
  17. quantum/cli/mq.py +582 -0
  18. quantum/cli/pkg.py +390 -0
  19. quantum/cli/runner.py +565 -0
  20. quantum/cli/server_process.py +159 -0
  21. quantum/cli/utils.py +334 -0
  22. quantum/compiler/__init__.py +30 -0
  23. quantum/compiler/base_generator.py +367 -0
  24. quantum/compiler/cli.py +295 -0
  25. quantum/compiler/expression_transformer.py +444 -0
  26. quantum/compiler/javascript/__init__.py +10 -0
  27. quantum/compiler/javascript/generator.py +659 -0
  28. quantum/compiler/optimizer.py +270 -0
  29. quantum/compiler/python/__init__.py +10 -0
  30. quantum/compiler/python/generator.py +883 -0
  31. quantum/compiler/python/runtime.py +863 -0
  32. quantum/compiler/transpiler.py +330 -0
  33. quantum/core/__init__.py +3 -0
  34. quantum/core/ast_nodes.py +2619 -0
  35. quantum/core/config_env.py +54 -0
  36. quantum/core/docs_links.py +8 -0
  37. quantum/core/expression_diagnostics.py +87 -0
  38. quantum/core/expression_stdlib.py +208 -0
  39. quantum/core/expressions.py +677 -0
  40. quantum/core/features/agents/src/__init__.py +30 -0
  41. quantum/core/features/agents/src/ast_node.py +540 -0
  42. quantum/core/features/conditionals/src/__init__.py +8 -0
  43. quantum/core/features/conditionals/src/ast_node.py +68 -0
  44. quantum/core/features/data_import/src/__init__.py +0 -0
  45. quantum/core/features/data_import/src/ast_node.py +292 -0
  46. quantum/core/features/data_import/src/runtime.py +533 -0
  47. quantum/core/features/dump/src/__init__.py +12 -0
  48. quantum/core/features/dump/src/ast_node.py +106 -0
  49. quantum/core/features/dump/src/parser.py +61 -0
  50. quantum/core/features/dump/src/runtime.py +246 -0
  51. quantum/core/features/functions/src/__init__.py +8 -0
  52. quantum/core/features/functions/src/ast_node.py +149 -0
  53. quantum/core/features/game_engine_2d/src/__init__.py +19 -0
  54. quantum/core/features/game_engine_2d/src/ast_nodes.py +1719 -0
  55. quantum/core/features/game_engine_2d/src/parser.py +983 -0
  56. quantum/core/features/invocation/src/__init__.py +0 -0
  57. quantum/core/features/invocation/src/ast_node.py +147 -0
  58. quantum/core/features/invocation/src/runtime.py +332 -0
  59. quantum/core/features/knowledge_base/src/__init__.py +6 -0
  60. quantum/core/features/knowledge_base/src/ast_node.py +113 -0
  61. quantum/core/features/knowledge_base/src/parser.py +82 -0
  62. quantum/core/features/logging/src/__init__.py +12 -0
  63. quantum/core/features/logging/src/ast_node.py +111 -0
  64. quantum/core/features/logging/src/parser.py +50 -0
  65. quantum/core/features/logging/src/runtime.py +190 -0
  66. quantum/core/features/loops/src/__init__.py +8 -0
  67. quantum/core/features/loops/src/ast_node.py +60 -0
  68. quantum/core/features/query/src/__init__.py +0 -0
  69. quantum/core/features/query/src/query_validators.py +20 -0
  70. quantum/core/features/state_management/src/__init__.py +11 -0
  71. quantum/core/features/state_management/src/ast_node.py +121 -0
  72. quantum/core/features/terminal_engine/src/__init__.py +21 -0
  73. quantum/core/features/terminal_engine/src/ast_nodes.py +560 -0
  74. quantum/core/features/terminal_engine/src/parser.py +361 -0
  75. quantum/core/features/testing_engine/src/__init__.py +41 -0
  76. quantum/core/features/testing_engine/src/ast_nodes.py +1212 -0
  77. quantum/core/features/testing_engine/src/parser.py +604 -0
  78. quantum/core/features/theming/src/__init__.py +48 -0
  79. quantum/core/features/theming/src/ast_node.py +137 -0
  80. quantum/core/features/theming/src/presets.py +405 -0
  81. quantum/core/features/ui_engine/src/__init__.py +20 -0
  82. quantum/core/features/ui_engine/src/ast_nodes.py +1913 -0
  83. quantum/core/features/ui_engine/src/parser.py +1192 -0
  84. quantum/core/features/websocket/src/__init__.py +24 -0
  85. quantum/core/features/websocket/src/ast_node.py +247 -0
  86. quantum/core/guards.py +53 -0
  87. quantum/core/html_compat.py +299 -0
  88. quantum/core/parser.py +1551 -0
  89. quantum/core/parser_registry.py +213 -0
  90. quantum/core/parsers/__init__.py +76 -0
  91. quantum/core/parsers/ai/__init__.py +12 -0
  92. quantum/core/parsers/ai/agent_parser.py +106 -0
  93. quantum/core/parsers/ai/knowledge_parser.py +86 -0
  94. quantum/core/parsers/ai/llm_parser.py +78 -0
  95. quantum/core/parsers/ai/team_parser.py +88 -0
  96. quantum/core/parsers/base.py +322 -0
  97. quantum/core/parsers/composition/__init__.py +10 -0
  98. quantum/core/parsers/composition/import_parser.py +50 -0
  99. quantum/core/parsers/composition/slot_parser.py +48 -0
  100. quantum/core/parsers/control_flow/__init__.py +11 -0
  101. quantum/core/parsers/control_flow/if_parser.py +71 -0
  102. quantum/core/parsers/control_flow/loop_parser.py +105 -0
  103. quantum/core/parsers/control_flow/set_parser.py +93 -0
  104. quantum/core/parsers/data/__init__.py +12 -0
  105. quantum/core/parsers/data/data_parser.py +229 -0
  106. quantum/core/parsers/data/invoke_parser.py +133 -0
  107. quantum/core/parsers/data/query_parser.py +213 -0
  108. quantum/core/parsers/data/transaction_parser.py +86 -0
  109. quantum/core/parsers/events/__init__.py +9 -0
  110. quantum/core/parsers/events/dispatch_event_parser.py +44 -0
  111. quantum/core/parsers/forms/__init__.py +11 -0
  112. quantum/core/parsers/forms/action_parser.py +79 -0
  113. quantum/core/parsers/forms/flash_parser.py +34 -0
  114. quantum/core/parsers/forms/redirect_parser.py +33 -0
  115. quantum/core/parsers/functions/__init__.py +11 -0
  116. quantum/core/parsers/functions/function_parser.py +98 -0
  117. quantum/core/parsers/functions/param_parser.py +73 -0
  118. quantum/core/parsers/functions/return_parser.py +31 -0
  119. quantum/core/parsers/html/__init__.py +10 -0
  120. quantum/core/parsers/html/component_call_parser.py +130 -0
  121. quantum/core/parsers/html/html_parser.py +115 -0
  122. quantum/core/parsers/jobs/__init__.py +11 -0
  123. quantum/core/parsers/jobs/job_parser.py +71 -0
  124. quantum/core/parsers/jobs/schedule_parser.py +62 -0
  125. quantum/core/parsers/jobs/thread_parser.py +57 -0
  126. quantum/core/parsers/messaging/__init__.py +17 -0
  127. quantum/core/parsers/messaging/message_ack_parser.py +30 -0
  128. quantum/core/parsers/messaging/message_nack_parser.py +30 -0
  129. quantum/core/parsers/messaging/message_parser.py +114 -0
  130. quantum/core/parsers/messaging/queue_parser.py +61 -0
  131. quantum/core/parsers/messaging/websocket_parser.py +121 -0
  132. quantum/core/parsers/routing/__init__.py +9 -0
  133. quantum/core/parsers/routing/route_parser.py +41 -0
  134. quantum/core/parsers/scripting/__init__.py +12 -0
  135. quantum/core/parsers/scripting/pyclass_parser.py +62 -0
  136. quantum/core/parsers/scripting/pydecorator_parser.py +68 -0
  137. quantum/core/parsers/scripting/pyimport_parser.py +52 -0
  138. quantum/core/parsers/scripting/python_parser.py +49 -0
  139. quantum/core/parsers/services/__init__.py +12 -0
  140. quantum/core/parsers/services/dump_parser.py +52 -0
  141. quantum/core/parsers/services/file_parser.py +48 -0
  142. quantum/core/parsers/services/log_parser.py +46 -0
  143. quantum/core/parsers/services/mail_parser.py +65 -0
  144. quantum/core/tiers.py +164 -0
  145. quantum/core/xml_lines.py +81 -0
  146. quantum/packages/__init__.py +28 -0
  147. quantum/packages/manager.py +413 -0
  148. quantum/packages/manifest.py +351 -0
  149. quantum/packages/registry.py +399 -0
  150. quantum/packages/resolver.py +336 -0
  151. quantum/plugins/__init__.py +33 -0
  152. quantum/plugins/hooks.py +329 -0
  153. quantum/plugins/loader.py +479 -0
  154. quantum/plugins/manifest.py +336 -0
  155. quantum/plugins/registry.py +371 -0
  156. quantum/runtime/__init__.py +25 -0
  157. quantum/runtime/action_handler.py +532 -0
  158. quantum/runtime/adapters/__init__.py +88 -0
  159. quantum/runtime/adapters/memory_adapter.py +690 -0
  160. quantum/runtime/adapters/rabbitmq_adapter.py +715 -0
  161. quantum/runtime/adapters/redis_adapter.py +582 -0
  162. quantum/runtime/adapters/sqlite_adapter.py +414 -0
  163. quantum/runtime/agent_service.py +1133 -0
  164. quantum/runtime/ast_cache.py +506 -0
  165. quantum/runtime/auth_service.py +267 -0
  166. quantum/runtime/component.py +1048 -0
  167. quantum/runtime/component_composer.py +133 -0
  168. quantum/runtime/component_resolver.py +174 -0
  169. quantum/runtime/conditions.py +54 -0
  170. quantum/runtime/database_service.py +595 -0
  171. quantum/runtime/db_schema.py +100 -0
  172. quantum/runtime/dev_panel.py +178 -0
  173. quantum/runtime/email_service.py +162 -0
  174. quantum/runtime/error_handler.py +295 -0
  175. quantum/runtime/execution_context.py +283 -0
  176. quantum/runtime/executor_registry.py +178 -0
  177. quantum/runtime/executors/__init__.py +71 -0
  178. quantum/runtime/executors/ai/__init__.py +12 -0
  179. quantum/runtime/executors/ai/agent_executor.py +217 -0
  180. quantum/runtime/executors/ai/knowledge_executor.py +114 -0
  181. quantum/runtime/executors/ai/llm_executor.py +153 -0
  182. quantum/runtime/executors/ai/team_executor.py +171 -0
  183. quantum/runtime/executors/base.py +264 -0
  184. quantum/runtime/executors/control_flow/__init__.py +12 -0
  185. quantum/runtime/executors/control_flow/if_executor.py +98 -0
  186. quantum/runtime/executors/control_flow/loop_executor.py +308 -0
  187. quantum/runtime/executors/control_flow/redirect_executor.py +43 -0
  188. quantum/runtime/executors/control_flow/set_executor.py +464 -0
  189. quantum/runtime/executors/data/__init__.py +12 -0
  190. quantum/runtime/executors/data/data_executor.py +156 -0
  191. quantum/runtime/executors/data/invoke_executor.py +228 -0
  192. quantum/runtime/executors/data/query_executor.py +290 -0
  193. quantum/runtime/executors/data/transaction_executor.py +91 -0
  194. quantum/runtime/executors/jobs/__init__.py +11 -0
  195. quantum/runtime/executors/jobs/job_executor.py +190 -0
  196. quantum/runtime/executors/jobs/schedule_executor.py +132 -0
  197. quantum/runtime/executors/jobs/thread_executor.py +127 -0
  198. quantum/runtime/executors/messaging/__init__.py +17 -0
  199. quantum/runtime/executors/messaging/message_ack_executor.py +51 -0
  200. quantum/runtime/executors/messaging/message_executor.py +174 -0
  201. quantum/runtime/executors/messaging/queue_executor.py +103 -0
  202. quantum/runtime/executors/messaging/websocket_executor.py +197 -0
  203. quantum/runtime/executors/scripting/__init__.py +11 -0
  204. quantum/runtime/executors/scripting/pyclass_executor.py +90 -0
  205. quantum/runtime/executors/scripting/pyimport_executor.py +81 -0
  206. quantum/runtime/executors/scripting/python_executor.py +249 -0
  207. quantum/runtime/executors/services/__init__.py +12 -0
  208. quantum/runtime/executors/services/dump_executor.py +72 -0
  209. quantum/runtime/executors/services/file_executor.py +89 -0
  210. quantum/runtime/executors/services/log_executor.py +77 -0
  211. quantum/runtime/executors/services/mail_executor.py +81 -0
  212. quantum/runtime/expression_cache.py +498 -0
  213. quantum/runtime/file_upload_service.py +326 -0
  214. quantum/runtime/function_registry.py +118 -0
  215. quantum/runtime/game_builder.py +166 -0
  216. quantum/runtime/game_code_generator.py +2371 -0
  217. quantum/runtime/game_templates.py +2006 -0
  218. quantum/runtime/godot_code_generator.py +4681 -0
  219. quantum/runtime/godot_templates.py +1449 -0
  220. quantum/runtime/job_executor.py +1599 -0
  221. quantum/runtime/knowledge_service.py +546 -0
  222. quantum/runtime/llm_cache.py +100 -0
  223. quantum/runtime/llm_providers.py +704 -0
  224. quantum/runtime/llm_service.py +287 -0
  225. quantum/runtime/local_server.py +28 -0
  226. quantum/runtime/logging_setup.py +141 -0
  227. quantum/runtime/message_broker.py +364 -0
  228. quantum/runtime/message_queue_service.py +571 -0
  229. quantum/runtime/param_validation.py +218 -0
  230. quantum/runtime/pypy_compat.py +317 -0
  231. quantum/runtime/python_bridge.py +698 -0
  232. quantum/runtime/query_validators.py +304 -0
  233. quantum/runtime/renderer.py +734 -0
  234. quantum/runtime/service_container.py +470 -0
  235. quantum/runtime/table_params.py +163 -0
  236. quantum/runtime/terminal_builder.py +76 -0
  237. quantum/runtime/terminal_code_generator.py +607 -0
  238. quantum/runtime/terminal_templates.py +243 -0
  239. quantum/runtime/testing_builder.py +77 -0
  240. quantum/runtime/testing_code_generator.py +833 -0
  241. quantum/runtime/testing_templates.py +85 -0
  242. quantum/runtime/ui_builder.py +222 -0
  243. quantum/runtime/ui_console.py +405 -0
  244. quantum/runtime/ui_desktop.py +56 -0
  245. quantum/runtime/ui_form_rules.py +193 -0
  246. quantum/runtime/ui_html_adapter.py +2567 -0
  247. quantum/runtime/ui_html_templates.py +2106 -0
  248. quantum/runtime/ui_mobile_adapter.py +1832 -0
  249. quantum/runtime/ui_mobile_templates.py +1003 -0
  250. quantum/runtime/ui_page_renderer.py +392 -0
  251. quantum/runtime/ui_pager.py +73 -0
  252. quantum/runtime/ui_table_edit.py +139 -0
  253. quantum/runtime/ui_textual_adapter.py +1866 -0
  254. quantum/runtime/ui_textual_templates.py +45 -0
  255. quantum/runtime/ui_tokens.py +465 -0
  256. quantum/runtime/ui_validator.py +365 -0
  257. quantum/runtime/ui_view.py +221 -0
  258. quantum/runtime/validators.py +256 -0
  259. quantum/runtime/web_server.py +2131 -0
  260. quantum/runtime/websocket_adapter.py +501 -0
  261. quantum/runtime/websocket_service.py +585 -0
  262. quantum/runtime/websocket_transport.py +289 -0
  263. quantum/runtime/wsgi.py +101 -0
  264. quantum/services.py +109 -0
  265. quantum/utils/__init__.py +1 -0
  266. quantum_admin/__init__.py +4 -0
  267. quantum_admin/assets/quantum-admin-connectors.js +123 -0
  268. quantum_admin/assets/quantum-admin.css +2058 -0
  269. quantum_admin/assets/quantum-source-highlight.js +106 -0
  270. quantum_admin/backend/__init__.py +4 -0
  271. quantum_admin/backend/audit_service.py +346 -0
  272. quantum_admin/backend/auth_service.py +394 -0
  273. quantum_admin/backend/component_discovery.py +766 -0
  274. quantum_admin/backend/config_generator.py +586 -0
  275. quantum_admin/backend/connector_service.py +1016 -0
  276. quantum_admin/backend/crud.py +557 -0
  277. quantum_admin/backend/database.py +226 -0
  278. quantum_admin/backend/db_setup_service.py +193 -0
  279. quantum_admin/backend/deploy_service.py +698 -0
  280. quantum_admin/backend/docker_service.py +422 -0
  281. quantum_admin/backend/environment_service.py +418 -0
  282. quantum_admin/backend/git_service.py +370 -0
  283. quantum_admin/backend/health_service.py +390 -0
  284. quantum_admin/backend/job_service.py +347 -0
  285. quantum_admin/backend/log_service.py +331 -0
  286. quantum_admin/backend/main.py +14426 -0
  287. quantum_admin/backend/models.py +986 -0
  288. quantum_admin/backend/pipeline_service.py +812 -0
  289. quantum_admin/backend/resource_manager.py +1118 -0
  290. quantum_admin/backend/schemas.py +419 -0
  291. quantum_admin/backend/secret_manager.py +277 -0
  292. quantum_admin/backend/settings_service.py +488 -0
  293. quantum_admin/backend/template_service.py +710 -0
  294. quantum_admin/backend/test_execution_service.py +364 -0
  295. quantum_admin/backend/test_generator.py +782 -0
  296. quantum_admin/backend/webhook_service.py +454 -0
  297. quantum_admin/backend/websocket_manager.py +360 -0
  298. quantum_admin/components/admin/_layout/AdminShell.q +121 -0
  299. quantum_admin/components/admin/agents.q +107 -0
  300. quantum_admin/components/admin/app/[name].q +558 -0
  301. quantum_admin/components/admin/applications.q +160 -0
  302. quantum_admin/components/admin/component/[...path].q +205 -0
  303. quantum_admin/components/admin/components.q +59 -0
  304. quantum_admin/components/admin/connectors.q +283 -0
  305. quantum_admin/components/admin/dashboard.q +86 -0
  306. quantum_admin/components/admin/database.q +95 -0
  307. quantum_admin/components/admin/features.q +69 -0
  308. quantum_admin/components/admin/index.q +12 -0
  309. quantum_admin/components/admin/jobs.q +75 -0
  310. quantum_admin/components/admin/login.q +65 -0
  311. quantum_admin/components/admin/logout.q +11 -0
  312. quantum_admin/components/admin/settings.q +174 -0
  313. quantum_admin/components/admin/source.q +45 -0
  314. quantum_admin/components/admin/tests.q +73 -0
  315. quantum_admin/run.py +13 -0
  316. quantum_admin/services/__init__.py +16 -0
  317. quantum_admin/services/_base.py +84 -0
  318. quantum_admin/services/_component_test_generator.py +205 -0
  319. quantum_admin/services/_yaml_editor.py +82 -0
  320. quantum_admin/services/apps.py +330 -0
  321. quantum_admin/services/auth.py +61 -0
  322. quantum_admin/services/components.py +210 -0
  323. quantum_admin/services/connectors.py +164 -0
  324. quantum_admin/services/projects.py +189 -0
  325. quantum_admin/services/repository.py +223 -0
  326. quantum_admin/services/settings.py +150 -0
  327. quantum_admin/services/yaml_import.py +118 -0
  328. quantum_framework-0.18.0.dist-info/METADATA +281 -0
  329. quantum_framework-0.18.0.dist-info/RECORD +333 -0
  330. quantum_framework-0.18.0.dist-info/WHEEL +5 -0
  331. quantum_framework-0.18.0.dist-info/entry_points.txt +2 -0
  332. quantum_framework-0.18.0.dist-info/licenses/LICENSE +21 -0
  333. quantum_framework-0.18.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,45 @@
1
+ """
2
+ UI Engine - Textual Templates
3
+
4
+ Provides:
5
+ - PyBuilder reuse from terminal_templates
6
+ - UI_TEXTUAL_APP_TEMPLATE: Textual app template for UI engine
7
+ """
8
+
9
+ from quantum.runtime.terminal_templates import PyBuilder, py_string, py_id, py_bool
10
+
11
+
12
+ # ==========================================================================
13
+ # Textual App Template
14
+ # ==========================================================================
15
+
16
+ UI_TEXTUAL_APP_TEMPLATE = '''\
17
+ """Quantum UI App - Generated Textual Application"""
18
+
19
+ from textual.app import App, ComposeResult
20
+ from textual.containers import Horizontal, Vertical, Grid, ScrollableContainer
21
+ from textual.widgets import (
22
+ Header, Footer, Static, Button, Input, DataTable,
23
+ Checkbox, Switch, ProgressBar, Tree, RichLog, Rule,
24
+ LoadingIndicator, Markdown, TabbedContent, TabPane,
25
+ Collapsible, OptionList, Select, Label,
26
+ )
27
+
28
+ {extra_imports}
29
+
30
+ class QuantumUIApp(App):
31
+ """Quantum UI Application"""
32
+
33
+ TITLE = {title}
34
+ CSS = """{css}"""
35
+
36
+ {bindings}
37
+ def compose(self) -> ComposeResult:
38
+ {compose_body}
39
+
40
+ {methods}
41
+
42
+ if __name__ == "__main__":
43
+ app = QuantumUIApp()
44
+ app.run()
45
+ '''
@@ -0,0 +1,465 @@
1
+ """
2
+ UI Engine - Design Tokens System
3
+
4
+ Provides a normalized design system that works across HTML and Textual targets.
5
+ Tokens ensure visual consistency when the same UI definition is rendered
6
+ in different environments.
7
+
8
+ Token Categories:
9
+ - Spacing: xs, sm, md, lg, xl (padding, margin, gap)
10
+ - Sizing: auto, fill, 1/2, 1/3, 1/4, 2/3, 3/4
11
+ - Colors: semantic (primary, secondary, success, danger, warning, info)
12
+ - Typography: xs, sm, md, lg, xl, 2xl
13
+
14
+ Usage:
15
+ from quantum.runtime.ui_tokens import TokenConverter
16
+
17
+ html_converter = TokenConverter('html')
18
+ textual_converter = TokenConverter('textual')
19
+
20
+ html_converter.spacing('md') # -> '16px'
21
+ textual_converter.spacing('md') # -> '2'
22
+ """
23
+
24
+ from typing import Dict, Optional, Tuple
25
+
26
+
27
+ # ==========================================================================
28
+ # Spacing Tokens
29
+ # ==========================================================================
30
+
31
+ # Spacing in abstract units (converted per-target)
32
+ SPACING_TOKENS = {
33
+ 'none': 0,
34
+ 'xs': 4,
35
+ 'sm': 8,
36
+ 'md': 16,
37
+ 'lg': 24,
38
+ 'xl': 32,
39
+ '2xl': 48,
40
+ }
41
+
42
+ # HTML: pixels
43
+ SPACING_HTML = {k: f"{v}px" for k, v in SPACING_TOKENS.items()}
44
+ SPACING_HTML['none'] = '0'
45
+
46
+ # Textual: character cells (roughly 8px per cell)
47
+ SPACING_TEXTUAL = {
48
+ 'none': '0',
49
+ 'xs': '1',
50
+ 'sm': '1',
51
+ 'md': '2',
52
+ 'lg': '3',
53
+ 'xl': '4',
54
+ '2xl': '6',
55
+ }
56
+
57
+
58
+ # ==========================================================================
59
+ # Sizing Tokens
60
+ # ==========================================================================
61
+
62
+ SIZE_TOKENS = {
63
+ 'auto': 'auto',
64
+ 'fill': 'full',
65
+ '1/2': '50%',
66
+ '1/3': '33.333%',
67
+ '1/4': '25%',
68
+ '2/3': '66.666%',
69
+ '3/4': '75%',
70
+ 'full': '100%',
71
+ }
72
+
73
+ # HTML sizing
74
+ SIZE_HTML = {
75
+ 'auto': 'auto',
76
+ 'fill': '100%',
77
+ 'full': '100%',
78
+ '1/2': '50%',
79
+ '1/3': '33.333%',
80
+ '1/4': '25%',
81
+ '2/3': '66.666%',
82
+ '3/4': '75%',
83
+ }
84
+
85
+ # Textual sizing (uses fr units or %)
86
+ SIZE_TEXTUAL = {
87
+ 'auto': 'auto',
88
+ 'fill': '1fr',
89
+ 'full': '100%',
90
+ '1/2': '1fr', # In a 2-column context
91
+ '1/3': '1fr', # In a 3-column context
92
+ '1/4': '1fr', # In a 4-column context
93
+ '2/3': '2fr',
94
+ '3/4': '3fr',
95
+ }
96
+
97
+
98
+ # ==========================================================================
99
+ # Color Tokens
100
+ # ==========================================================================
101
+
102
+ # Semantic color names
103
+ COLOR_SEMANTIC = {
104
+ 'primary', 'secondary', 'success', 'danger',
105
+ 'warning', 'info', 'light', 'dark',
106
+ 'text', 'background', 'border', 'muted',
107
+ }
108
+
109
+ # HTML: CSS custom properties
110
+ COLOR_HTML = {
111
+ 'primary': 'var(--q-primary)',
112
+ 'secondary': 'var(--q-secondary)',
113
+ 'success': 'var(--q-success)',
114
+ 'danger': 'var(--q-danger)',
115
+ 'warning': 'var(--q-warning)',
116
+ 'info': 'var(--q-info)',
117
+ 'light': 'var(--q-light)',
118
+ 'dark': 'var(--q-dark)',
119
+ 'text': 'var(--q-text)',
120
+ 'background': 'var(--q-bg)',
121
+ 'border': 'var(--q-border)',
122
+ 'muted': 'var(--q-secondary)',
123
+ }
124
+
125
+ # Textual: theme variables ($ prefix)
126
+ COLOR_TEXTUAL = {
127
+ 'primary': '$primary',
128
+ 'secondary': '$secondary',
129
+ 'success': '$success',
130
+ 'danger': '$error',
131
+ 'warning': '$warning',
132
+ 'info': '$accent',
133
+ 'light': '$surface',
134
+ 'dark': '$background',
135
+ 'text': '$text',
136
+ 'background': '$background',
137
+ 'border': '$primary-background',
138
+ 'muted': '$text-muted',
139
+ }
140
+
141
+
142
+ # ==========================================================================
143
+ # Typography Tokens
144
+ # ==========================================================================
145
+
146
+ FONT_SIZE_TOKENS = {
147
+ 'xs': 0.75, # 12px
148
+ 'sm': 0.875, # 14px
149
+ 'md': 1.0, # 16px
150
+ 'lg': 1.25, # 20px
151
+ 'xl': 1.5, # 24px
152
+ '2xl': 2.0, # 32px
153
+ }
154
+
155
+ FONT_SIZE_HTML = {
156
+ 'xs': 'var(--q-font-xs)',
157
+ 'sm': 'var(--q-font-sm)',
158
+ 'md': 'var(--q-font-md)',
159
+ 'lg': 'var(--q-font-lg)',
160
+ 'xl': 'var(--q-font-xl)',
161
+ '2xl': 'var(--q-font-2xl)',
162
+ }
163
+
164
+ # Textual doesn't support font sizes in the same way
165
+ # We use text styles instead
166
+ FONT_SIZE_TEXTUAL = {
167
+ 'xs': '', # No direct mapping
168
+ 'sm': '', # No direct mapping
169
+ 'md': '', # Default
170
+ 'lg': 'bold', # Emphasize with bold
171
+ 'xl': 'bold',
172
+ '2xl': 'bold',
173
+ }
174
+
175
+
176
+ # ==========================================================================
177
+ # Align/Justify Tokens
178
+ # ==========================================================================
179
+
180
+ ALIGN_TOKENS = {'start', 'center', 'end', 'stretch'}
181
+
182
+ ALIGN_HTML = {
183
+ 'start': 'flex-start',
184
+ 'center': 'center',
185
+ 'end': 'flex-end',
186
+ 'stretch': 'stretch',
187
+ }
188
+
189
+ # Textual uses different alignment syntax: "horizontal vertical"
190
+ ALIGN_TEXTUAL = {
191
+ 'start': 'left',
192
+ 'center': 'center',
193
+ 'end': 'right',
194
+ 'stretch': 'center', # No direct equivalent
195
+ }
196
+
197
+ JUSTIFY_TOKENS = {'start', 'center', 'end', 'between', 'around'}
198
+
199
+ JUSTIFY_HTML = {
200
+ 'start': 'flex-start',
201
+ 'center': 'center',
202
+ 'end': 'flex-end',
203
+ 'between': 'space-between',
204
+ 'around': 'space-around',
205
+ }
206
+
207
+ # Textual doesn't have justify-content equivalent
208
+ # We approximate with alignment
209
+ JUSTIFY_TEXTUAL = {
210
+ 'start': 'left',
211
+ 'center': 'center',
212
+ 'end': 'right',
213
+ 'between': 'center', # No equivalent, use center
214
+ 'around': 'center', # No equivalent, use center
215
+ }
216
+
217
+
218
+ # ==========================================================================
219
+ # Token Converter
220
+ # ==========================================================================
221
+
222
+ class TokenConverter:
223
+ """Converts design tokens to target-specific values."""
224
+
225
+ def __init__(self, target: str = 'html'):
226
+ """
227
+ Args:
228
+ target: 'html' or 'textual'
229
+ """
230
+ self.target = target.lower()
231
+ if self.target not in ('html', 'textual'):
232
+ raise ValueError(f"Unknown target: {target}")
233
+
234
+ def spacing(self, value: str) -> str:
235
+ """Convert spacing token or raw value to target format.
236
+
237
+ Accepts:
238
+ - Token: 'sm', 'md', 'lg', etc.
239
+ - Raw pixel: '16', '16px'
240
+ - Raw percentage: '10%'
241
+ """
242
+ if not value:
243
+ return ''
244
+
245
+ value_lower = value.lower().strip()
246
+
247
+ # Check if it's a token
248
+ if value_lower in SPACING_TOKENS:
249
+ if self.target == 'html':
250
+ return SPACING_HTML[value_lower]
251
+ else:
252
+ return SPACING_TEXTUAL[value_lower]
253
+
254
+ # Raw value - convert for target
255
+ return self._convert_raw_spacing(value)
256
+
257
+ def _convert_raw_spacing(self, value: str) -> str:
258
+ """Convert raw spacing value to target format."""
259
+ if self.target == 'html':
260
+ # HTML accepts px, %, em, etc.
261
+ if value.endswith(('px', '%', 'em', 'rem')):
262
+ return value
263
+ try:
264
+ int(value)
265
+ return f"{value}px"
266
+ except ValueError:
267
+ return value
268
+ else:
269
+ # Textual uses character cells
270
+ if value.endswith('px'):
271
+ px = int(value[:-2])
272
+ return str(max(1, px // 8))
273
+ if value.endswith('%'):
274
+ return value # Textual supports %
275
+ try:
276
+ px = int(value)
277
+ return str(max(1, px // 8))
278
+ except ValueError:
279
+ return '1' # Default to 1 cell
280
+
281
+ def size(self, value: str) -> str:
282
+ """Convert size token or raw value to target format.
283
+
284
+ Accepts:
285
+ - Token: 'fill', 'auto', '1/2', '1/3', etc.
286
+ - Raw pixel: '200', '200px'
287
+ - Raw percentage: '50%'
288
+ """
289
+ if not value:
290
+ return ''
291
+
292
+ value_lower = value.lower().strip()
293
+
294
+ # Check if it's a token
295
+ if value_lower in SIZE_TOKENS:
296
+ if self.target == 'html':
297
+ return SIZE_HTML.get(value_lower, value)
298
+ else:
299
+ return SIZE_TEXTUAL.get(value_lower, value)
300
+
301
+ # Raw value
302
+ return self._convert_raw_size(value)
303
+
304
+ def _convert_raw_size(self, value: str) -> str:
305
+ """Convert raw size value to target format."""
306
+ if self.target == 'html':
307
+ if value == 'fill':
308
+ return '100%'
309
+ if value.endswith(('px', '%', 'em', 'rem', 'vw', 'vh')):
310
+ return value
311
+ try:
312
+ int(value)
313
+ return f"{value}px"
314
+ except ValueError:
315
+ return value
316
+ else:
317
+ # Textual
318
+ if value == 'fill':
319
+ return '100%'
320
+ if value.endswith('%'):
321
+ return value
322
+ if value.endswith('px'):
323
+ px = int(value[:-2])
324
+ return str(max(1, px // 8)) # Convert to cells
325
+ try:
326
+ px = int(value)
327
+ return str(max(1, px // 8))
328
+ except ValueError:
329
+ return 'auto'
330
+
331
+ def color(self, value: str) -> str:
332
+ """Convert color token or raw value to target format.
333
+
334
+ Accepts:
335
+ - Token: 'primary', 'success', etc.
336
+ - Raw hex: '#ff0000'
337
+ - Raw name: 'red', 'blue'
338
+ """
339
+ if not value:
340
+ return ''
341
+
342
+ value_lower = value.lower().strip()
343
+
344
+ # Check if it's a semantic token
345
+ if value_lower in COLOR_SEMANTIC:
346
+ if self.target == 'html':
347
+ return COLOR_HTML.get(value_lower, value)
348
+ else:
349
+ return COLOR_TEXTUAL.get(value_lower, value)
350
+
351
+ # Raw color value
352
+ if self.target == 'html':
353
+ return value # HTML accepts any CSS color
354
+ else:
355
+ # Textual accepts color names and some formats
356
+ return self._convert_raw_color_textual(value)
357
+
358
+ def _convert_raw_color_textual(self, value: str) -> str:
359
+ """Convert raw color for Textual."""
360
+ # Textual supports: color names, rgb(), ansi colors
361
+ if value.startswith('#'):
362
+ # Convert hex to rgb for better compatibility
363
+ return value # Textual 0.40+ supports hex
364
+ return value
365
+
366
+ def font_size(self, value: str) -> str:
367
+ """Convert font size token to target format."""
368
+ if not value:
369
+ return ''
370
+
371
+ value_lower = value.lower().strip()
372
+
373
+ if value_lower in FONT_SIZE_TOKENS:
374
+ if self.target == 'html':
375
+ return FONT_SIZE_HTML.get(value_lower, value)
376
+ else:
377
+ return FONT_SIZE_TEXTUAL.get(value_lower, '')
378
+
379
+ # Raw value
380
+ return value if self.target == 'html' else ''
381
+
382
+ def align(self, value: str) -> str:
383
+ """Convert align token to target format."""
384
+ if not value:
385
+ return ''
386
+
387
+ value_lower = value.lower().strip()
388
+
389
+ if self.target == 'html':
390
+ return ALIGN_HTML.get(value_lower, value)
391
+ else:
392
+ return ALIGN_TEXTUAL.get(value_lower, 'center')
393
+
394
+ def justify(self, value: str) -> str:
395
+ """Convert justify token to target format."""
396
+ if not value:
397
+ return ''
398
+
399
+ value_lower = value.lower().strip()
400
+
401
+ if self.target == 'html':
402
+ return JUSTIFY_HTML.get(value_lower, value)
403
+ else:
404
+ return JUSTIFY_TEXTUAL.get(value_lower, 'center')
405
+
406
+
407
+ # ==========================================================================
408
+ # Compatibility Warnings
409
+ # ==========================================================================
410
+
411
+ # Features that don't translate well between targets
412
+ COMPATIBILITY_WARNINGS = {
413
+ 'gap': {
414
+ 'textual': "gap is not supported in Textual; using margin on children",
415
+ },
416
+ 'justify_between': {
417
+ 'textual': "justify='between' has no Textual equivalent; items will be centered",
418
+ },
419
+ 'justify_around': {
420
+ 'textual': "justify='around' has no Textual equivalent; items will be centered",
421
+ },
422
+ 'image': {
423
+ 'textual': "Images cannot be displayed in terminal; showing placeholder text",
424
+ },
425
+ 'link_external': {
426
+ 'textual': "External links are not clickable in terminal; showing as text",
427
+ },
428
+ 'font_size': {
429
+ 'textual': "Font sizes are not adjustable in terminal; using text weight instead",
430
+ },
431
+ 'animation': {
432
+ 'textual': "CSS animations are not supported in terminal",
433
+ },
434
+ 'pixel_units': {
435
+ 'textual': "Pixel values are converted to character cells (÷8)",
436
+ },
437
+ }
438
+
439
+
440
+ def get_compatibility_warnings(features_used: set, target: str) -> list:
441
+ """Get list of compatibility warnings for features used."""
442
+ warnings = []
443
+ for feature in features_used:
444
+ if feature in COMPATIBILITY_WARNINGS:
445
+ warning = COMPATIBILITY_WARNINGS[feature].get(target)
446
+ if warning:
447
+ warnings.append(f"[{feature}] {warning}")
448
+ return warnings
449
+
450
+
451
+ # ==========================================================================
452
+ # Utility: Check if value is a token
453
+ # ==========================================================================
454
+
455
+ def is_spacing_token(value: str) -> bool:
456
+ return value.lower().strip() in SPACING_TOKENS
457
+
458
+ def is_size_token(value: str) -> bool:
459
+ return value.lower().strip() in SIZE_TOKENS
460
+
461
+ def is_color_token(value: str) -> bool:
462
+ return value.lower().strip() in COLOR_SEMANTIC
463
+
464
+ def is_font_token(value: str) -> bool:
465
+ return value.lower().strip() in FONT_SIZE_TOKENS