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.
- quantum/__init__.py +1 -0
- quantum/cli/__init__.py +2 -0
- quantum/cli/admin.py +131 -0
- quantum/cli/check.py +223 -0
- quantum/cli/commands/__init__.py +15 -0
- quantum/cli/commands/build.py +414 -0
- quantum/cli/commands/dev.py +185 -0
- quantum/cli/commands/docs.py +329 -0
- quantum/cli/commands/lint.py +523 -0
- quantum/cli/commands/migrate.py +548 -0
- quantum/cli/commands/new.py +622 -0
- quantum/cli/commands/serve.py +190 -0
- quantum/cli/commands/test.py +193 -0
- quantum/cli/deploy.py +810 -0
- quantum/cli/hot_reload.py +951 -0
- quantum/cli/jobs.py +356 -0
- quantum/cli/mq.py +582 -0
- quantum/cli/pkg.py +390 -0
- quantum/cli/runner.py +565 -0
- quantum/cli/server_process.py +159 -0
- quantum/cli/utils.py +334 -0
- quantum/compiler/__init__.py +30 -0
- quantum/compiler/base_generator.py +367 -0
- quantum/compiler/cli.py +295 -0
- quantum/compiler/expression_transformer.py +444 -0
- quantum/compiler/javascript/__init__.py +10 -0
- quantum/compiler/javascript/generator.py +659 -0
- quantum/compiler/optimizer.py +270 -0
- quantum/compiler/python/__init__.py +10 -0
- quantum/compiler/python/generator.py +883 -0
- quantum/compiler/python/runtime.py +863 -0
- quantum/compiler/transpiler.py +330 -0
- quantum/core/__init__.py +3 -0
- quantum/core/ast_nodes.py +2619 -0
- quantum/core/config_env.py +54 -0
- quantum/core/docs_links.py +8 -0
- quantum/core/expression_diagnostics.py +87 -0
- quantum/core/expression_stdlib.py +208 -0
- quantum/core/expressions.py +677 -0
- quantum/core/features/agents/src/__init__.py +30 -0
- quantum/core/features/agents/src/ast_node.py +540 -0
- quantum/core/features/conditionals/src/__init__.py +8 -0
- quantum/core/features/conditionals/src/ast_node.py +68 -0
- quantum/core/features/data_import/src/__init__.py +0 -0
- quantum/core/features/data_import/src/ast_node.py +292 -0
- quantum/core/features/data_import/src/runtime.py +533 -0
- quantum/core/features/dump/src/__init__.py +12 -0
- quantum/core/features/dump/src/ast_node.py +106 -0
- quantum/core/features/dump/src/parser.py +61 -0
- quantum/core/features/dump/src/runtime.py +246 -0
- quantum/core/features/functions/src/__init__.py +8 -0
- quantum/core/features/functions/src/ast_node.py +149 -0
- quantum/core/features/game_engine_2d/src/__init__.py +19 -0
- quantum/core/features/game_engine_2d/src/ast_nodes.py +1719 -0
- quantum/core/features/game_engine_2d/src/parser.py +983 -0
- quantum/core/features/invocation/src/__init__.py +0 -0
- quantum/core/features/invocation/src/ast_node.py +147 -0
- quantum/core/features/invocation/src/runtime.py +332 -0
- quantum/core/features/knowledge_base/src/__init__.py +6 -0
- quantum/core/features/knowledge_base/src/ast_node.py +113 -0
- quantum/core/features/knowledge_base/src/parser.py +82 -0
- quantum/core/features/logging/src/__init__.py +12 -0
- quantum/core/features/logging/src/ast_node.py +111 -0
- quantum/core/features/logging/src/parser.py +50 -0
- quantum/core/features/logging/src/runtime.py +190 -0
- quantum/core/features/loops/src/__init__.py +8 -0
- quantum/core/features/loops/src/ast_node.py +60 -0
- quantum/core/features/query/src/__init__.py +0 -0
- quantum/core/features/query/src/query_validators.py +20 -0
- quantum/core/features/state_management/src/__init__.py +11 -0
- quantum/core/features/state_management/src/ast_node.py +121 -0
- quantum/core/features/terminal_engine/src/__init__.py +21 -0
- quantum/core/features/terminal_engine/src/ast_nodes.py +560 -0
- quantum/core/features/terminal_engine/src/parser.py +361 -0
- quantum/core/features/testing_engine/src/__init__.py +41 -0
- quantum/core/features/testing_engine/src/ast_nodes.py +1212 -0
- quantum/core/features/testing_engine/src/parser.py +604 -0
- quantum/core/features/theming/src/__init__.py +48 -0
- quantum/core/features/theming/src/ast_node.py +137 -0
- quantum/core/features/theming/src/presets.py +405 -0
- quantum/core/features/ui_engine/src/__init__.py +20 -0
- quantum/core/features/ui_engine/src/ast_nodes.py +1913 -0
- quantum/core/features/ui_engine/src/parser.py +1192 -0
- quantum/core/features/websocket/src/__init__.py +24 -0
- quantum/core/features/websocket/src/ast_node.py +247 -0
- quantum/core/guards.py +53 -0
- quantum/core/html_compat.py +299 -0
- quantum/core/parser.py +1551 -0
- quantum/core/parser_registry.py +213 -0
- quantum/core/parsers/__init__.py +76 -0
- quantum/core/parsers/ai/__init__.py +12 -0
- quantum/core/parsers/ai/agent_parser.py +106 -0
- quantum/core/parsers/ai/knowledge_parser.py +86 -0
- quantum/core/parsers/ai/llm_parser.py +78 -0
- quantum/core/parsers/ai/team_parser.py +88 -0
- quantum/core/parsers/base.py +322 -0
- quantum/core/parsers/composition/__init__.py +10 -0
- quantum/core/parsers/composition/import_parser.py +50 -0
- quantum/core/parsers/composition/slot_parser.py +48 -0
- quantum/core/parsers/control_flow/__init__.py +11 -0
- quantum/core/parsers/control_flow/if_parser.py +71 -0
- quantum/core/parsers/control_flow/loop_parser.py +105 -0
- quantum/core/parsers/control_flow/set_parser.py +93 -0
- quantum/core/parsers/data/__init__.py +12 -0
- quantum/core/parsers/data/data_parser.py +229 -0
- quantum/core/parsers/data/invoke_parser.py +133 -0
- quantum/core/parsers/data/query_parser.py +213 -0
- quantum/core/parsers/data/transaction_parser.py +86 -0
- quantum/core/parsers/events/__init__.py +9 -0
- quantum/core/parsers/events/dispatch_event_parser.py +44 -0
- quantum/core/parsers/forms/__init__.py +11 -0
- quantum/core/parsers/forms/action_parser.py +79 -0
- quantum/core/parsers/forms/flash_parser.py +34 -0
- quantum/core/parsers/forms/redirect_parser.py +33 -0
- quantum/core/parsers/functions/__init__.py +11 -0
- quantum/core/parsers/functions/function_parser.py +98 -0
- quantum/core/parsers/functions/param_parser.py +73 -0
- quantum/core/parsers/functions/return_parser.py +31 -0
- quantum/core/parsers/html/__init__.py +10 -0
- quantum/core/parsers/html/component_call_parser.py +130 -0
- quantum/core/parsers/html/html_parser.py +115 -0
- quantum/core/parsers/jobs/__init__.py +11 -0
- quantum/core/parsers/jobs/job_parser.py +71 -0
- quantum/core/parsers/jobs/schedule_parser.py +62 -0
- quantum/core/parsers/jobs/thread_parser.py +57 -0
- quantum/core/parsers/messaging/__init__.py +17 -0
- quantum/core/parsers/messaging/message_ack_parser.py +30 -0
- quantum/core/parsers/messaging/message_nack_parser.py +30 -0
- quantum/core/parsers/messaging/message_parser.py +114 -0
- quantum/core/parsers/messaging/queue_parser.py +61 -0
- quantum/core/parsers/messaging/websocket_parser.py +121 -0
- quantum/core/parsers/routing/__init__.py +9 -0
- quantum/core/parsers/routing/route_parser.py +41 -0
- quantum/core/parsers/scripting/__init__.py +12 -0
- quantum/core/parsers/scripting/pyclass_parser.py +62 -0
- quantum/core/parsers/scripting/pydecorator_parser.py +68 -0
- quantum/core/parsers/scripting/pyimport_parser.py +52 -0
- quantum/core/parsers/scripting/python_parser.py +49 -0
- quantum/core/parsers/services/__init__.py +12 -0
- quantum/core/parsers/services/dump_parser.py +52 -0
- quantum/core/parsers/services/file_parser.py +48 -0
- quantum/core/parsers/services/log_parser.py +46 -0
- quantum/core/parsers/services/mail_parser.py +65 -0
- quantum/core/tiers.py +164 -0
- quantum/core/xml_lines.py +81 -0
- quantum/packages/__init__.py +28 -0
- quantum/packages/manager.py +413 -0
- quantum/packages/manifest.py +351 -0
- quantum/packages/registry.py +399 -0
- quantum/packages/resolver.py +336 -0
- quantum/plugins/__init__.py +33 -0
- quantum/plugins/hooks.py +329 -0
- quantum/plugins/loader.py +479 -0
- quantum/plugins/manifest.py +336 -0
- quantum/plugins/registry.py +371 -0
- quantum/runtime/__init__.py +25 -0
- quantum/runtime/action_handler.py +532 -0
- quantum/runtime/adapters/__init__.py +88 -0
- quantum/runtime/adapters/memory_adapter.py +690 -0
- quantum/runtime/adapters/rabbitmq_adapter.py +715 -0
- quantum/runtime/adapters/redis_adapter.py +582 -0
- quantum/runtime/adapters/sqlite_adapter.py +414 -0
- quantum/runtime/agent_service.py +1133 -0
- quantum/runtime/ast_cache.py +506 -0
- quantum/runtime/auth_service.py +267 -0
- quantum/runtime/component.py +1048 -0
- quantum/runtime/component_composer.py +133 -0
- quantum/runtime/component_resolver.py +174 -0
- quantum/runtime/conditions.py +54 -0
- quantum/runtime/database_service.py +595 -0
- quantum/runtime/db_schema.py +100 -0
- quantum/runtime/dev_panel.py +178 -0
- quantum/runtime/email_service.py +162 -0
- quantum/runtime/error_handler.py +295 -0
- quantum/runtime/execution_context.py +283 -0
- quantum/runtime/executor_registry.py +178 -0
- quantum/runtime/executors/__init__.py +71 -0
- quantum/runtime/executors/ai/__init__.py +12 -0
- quantum/runtime/executors/ai/agent_executor.py +217 -0
- quantum/runtime/executors/ai/knowledge_executor.py +114 -0
- quantum/runtime/executors/ai/llm_executor.py +153 -0
- quantum/runtime/executors/ai/team_executor.py +171 -0
- quantum/runtime/executors/base.py +264 -0
- quantum/runtime/executors/control_flow/__init__.py +12 -0
- quantum/runtime/executors/control_flow/if_executor.py +98 -0
- quantum/runtime/executors/control_flow/loop_executor.py +308 -0
- quantum/runtime/executors/control_flow/redirect_executor.py +43 -0
- quantum/runtime/executors/control_flow/set_executor.py +464 -0
- quantum/runtime/executors/data/__init__.py +12 -0
- quantum/runtime/executors/data/data_executor.py +156 -0
- quantum/runtime/executors/data/invoke_executor.py +228 -0
- quantum/runtime/executors/data/query_executor.py +290 -0
- quantum/runtime/executors/data/transaction_executor.py +91 -0
- quantum/runtime/executors/jobs/__init__.py +11 -0
- quantum/runtime/executors/jobs/job_executor.py +190 -0
- quantum/runtime/executors/jobs/schedule_executor.py +132 -0
- quantum/runtime/executors/jobs/thread_executor.py +127 -0
- quantum/runtime/executors/messaging/__init__.py +17 -0
- quantum/runtime/executors/messaging/message_ack_executor.py +51 -0
- quantum/runtime/executors/messaging/message_executor.py +174 -0
- quantum/runtime/executors/messaging/queue_executor.py +103 -0
- quantum/runtime/executors/messaging/websocket_executor.py +197 -0
- quantum/runtime/executors/scripting/__init__.py +11 -0
- quantum/runtime/executors/scripting/pyclass_executor.py +90 -0
- quantum/runtime/executors/scripting/pyimport_executor.py +81 -0
- quantum/runtime/executors/scripting/python_executor.py +249 -0
- quantum/runtime/executors/services/__init__.py +12 -0
- quantum/runtime/executors/services/dump_executor.py +72 -0
- quantum/runtime/executors/services/file_executor.py +89 -0
- quantum/runtime/executors/services/log_executor.py +77 -0
- quantum/runtime/executors/services/mail_executor.py +81 -0
- quantum/runtime/expression_cache.py +498 -0
- quantum/runtime/file_upload_service.py +326 -0
- quantum/runtime/function_registry.py +118 -0
- quantum/runtime/game_builder.py +166 -0
- quantum/runtime/game_code_generator.py +2371 -0
- quantum/runtime/game_templates.py +2006 -0
- quantum/runtime/godot_code_generator.py +4681 -0
- quantum/runtime/godot_templates.py +1449 -0
- quantum/runtime/job_executor.py +1599 -0
- quantum/runtime/knowledge_service.py +546 -0
- quantum/runtime/llm_cache.py +100 -0
- quantum/runtime/llm_providers.py +704 -0
- quantum/runtime/llm_service.py +287 -0
- quantum/runtime/local_server.py +28 -0
- quantum/runtime/logging_setup.py +141 -0
- quantum/runtime/message_broker.py +364 -0
- quantum/runtime/message_queue_service.py +571 -0
- quantum/runtime/param_validation.py +218 -0
- quantum/runtime/pypy_compat.py +317 -0
- quantum/runtime/python_bridge.py +698 -0
- quantum/runtime/query_validators.py +304 -0
- quantum/runtime/renderer.py +734 -0
- quantum/runtime/service_container.py +470 -0
- quantum/runtime/table_params.py +163 -0
- quantum/runtime/terminal_builder.py +76 -0
- quantum/runtime/terminal_code_generator.py +607 -0
- quantum/runtime/terminal_templates.py +243 -0
- quantum/runtime/testing_builder.py +77 -0
- quantum/runtime/testing_code_generator.py +833 -0
- quantum/runtime/testing_templates.py +85 -0
- quantum/runtime/ui_builder.py +222 -0
- quantum/runtime/ui_console.py +405 -0
- quantum/runtime/ui_desktop.py +56 -0
- quantum/runtime/ui_form_rules.py +193 -0
- quantum/runtime/ui_html_adapter.py +2567 -0
- quantum/runtime/ui_html_templates.py +2106 -0
- quantum/runtime/ui_mobile_adapter.py +1832 -0
- quantum/runtime/ui_mobile_templates.py +1003 -0
- quantum/runtime/ui_page_renderer.py +392 -0
- quantum/runtime/ui_pager.py +73 -0
- quantum/runtime/ui_table_edit.py +139 -0
- quantum/runtime/ui_textual_adapter.py +1866 -0
- quantum/runtime/ui_textual_templates.py +45 -0
- quantum/runtime/ui_tokens.py +465 -0
- quantum/runtime/ui_validator.py +365 -0
- quantum/runtime/ui_view.py +221 -0
- quantum/runtime/validators.py +256 -0
- quantum/runtime/web_server.py +2131 -0
- quantum/runtime/websocket_adapter.py +501 -0
- quantum/runtime/websocket_service.py +585 -0
- quantum/runtime/websocket_transport.py +289 -0
- quantum/runtime/wsgi.py +101 -0
- quantum/services.py +109 -0
- quantum/utils/__init__.py +1 -0
- quantum_admin/__init__.py +4 -0
- quantum_admin/assets/quantum-admin-connectors.js +123 -0
- quantum_admin/assets/quantum-admin.css +2058 -0
- quantum_admin/assets/quantum-source-highlight.js +106 -0
- quantum_admin/backend/__init__.py +4 -0
- quantum_admin/backend/audit_service.py +346 -0
- quantum_admin/backend/auth_service.py +394 -0
- quantum_admin/backend/component_discovery.py +766 -0
- quantum_admin/backend/config_generator.py +586 -0
- quantum_admin/backend/connector_service.py +1016 -0
- quantum_admin/backend/crud.py +557 -0
- quantum_admin/backend/database.py +226 -0
- quantum_admin/backend/db_setup_service.py +193 -0
- quantum_admin/backend/deploy_service.py +698 -0
- quantum_admin/backend/docker_service.py +422 -0
- quantum_admin/backend/environment_service.py +418 -0
- quantum_admin/backend/git_service.py +370 -0
- quantum_admin/backend/health_service.py +390 -0
- quantum_admin/backend/job_service.py +347 -0
- quantum_admin/backend/log_service.py +331 -0
- quantum_admin/backend/main.py +14426 -0
- quantum_admin/backend/models.py +986 -0
- quantum_admin/backend/pipeline_service.py +812 -0
- quantum_admin/backend/resource_manager.py +1118 -0
- quantum_admin/backend/schemas.py +419 -0
- quantum_admin/backend/secret_manager.py +277 -0
- quantum_admin/backend/settings_service.py +488 -0
- quantum_admin/backend/template_service.py +710 -0
- quantum_admin/backend/test_execution_service.py +364 -0
- quantum_admin/backend/test_generator.py +782 -0
- quantum_admin/backend/webhook_service.py +454 -0
- quantum_admin/backend/websocket_manager.py +360 -0
- quantum_admin/components/admin/_layout/AdminShell.q +121 -0
- quantum_admin/components/admin/agents.q +107 -0
- quantum_admin/components/admin/app/[name].q +558 -0
- quantum_admin/components/admin/applications.q +160 -0
- quantum_admin/components/admin/component/[...path].q +205 -0
- quantum_admin/components/admin/components.q +59 -0
- quantum_admin/components/admin/connectors.q +283 -0
- quantum_admin/components/admin/dashboard.q +86 -0
- quantum_admin/components/admin/database.q +95 -0
- quantum_admin/components/admin/features.q +69 -0
- quantum_admin/components/admin/index.q +12 -0
- quantum_admin/components/admin/jobs.q +75 -0
- quantum_admin/components/admin/login.q +65 -0
- quantum_admin/components/admin/logout.q +11 -0
- quantum_admin/components/admin/settings.q +174 -0
- quantum_admin/components/admin/source.q +45 -0
- quantum_admin/components/admin/tests.q +73 -0
- quantum_admin/run.py +13 -0
- quantum_admin/services/__init__.py +16 -0
- quantum_admin/services/_base.py +84 -0
- quantum_admin/services/_component_test_generator.py +205 -0
- quantum_admin/services/_yaml_editor.py +82 -0
- quantum_admin/services/apps.py +330 -0
- quantum_admin/services/auth.py +61 -0
- quantum_admin/services/components.py +210 -0
- quantum_admin/services/connectors.py +164 -0
- quantum_admin/services/projects.py +189 -0
- quantum_admin/services/repository.py +223 -0
- quantum_admin/services/settings.py +150 -0
- quantum_admin/services/yaml_import.py +118 -0
- quantum_framework-0.18.0.dist-info/METADATA +281 -0
- quantum_framework-0.18.0.dist-info/RECORD +333 -0
- quantum_framework-0.18.0.dist-info/WHEEL +5 -0
- quantum_framework-0.18.0.dist-info/entry_points.txt +2 -0
- quantum_framework-0.18.0.dist-info/licenses/LICENSE +21 -0
- quantum_framework-0.18.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Quantum Package Manifest Handler
|
|
3
|
+
|
|
4
|
+
Handles parsing and validation of quantum.yaml package manifests.
|
|
5
|
+
|
|
6
|
+
Package structure:
|
|
7
|
+
my-component/
|
|
8
|
+
├── quantum.yaml # Package manifest
|
|
9
|
+
├── src/
|
|
10
|
+
│ └── MyComponent.q # Component file
|
|
11
|
+
├── examples/
|
|
12
|
+
│ └── demo.q
|
|
13
|
+
└── README.md
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
import re
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Dict, List, Optional, Any
|
|
20
|
+
from dataclasses import dataclass, field
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
import yaml
|
|
24
|
+
except ImportError:
|
|
25
|
+
yaml = None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ManifestError(Exception):
|
|
29
|
+
"""Error parsing or validating package manifest."""
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class PackageManifest:
|
|
35
|
+
"""
|
|
36
|
+
Represents a quantum.yaml package manifest.
|
|
37
|
+
|
|
38
|
+
Attributes:
|
|
39
|
+
name: Package name (lowercase, alphanumeric, hyphens allowed)
|
|
40
|
+
version: Semantic version (e.g., "1.0.0")
|
|
41
|
+
description: Package description
|
|
42
|
+
author: Package author
|
|
43
|
+
license: License identifier (e.g., "MIT", "Apache-2.0")
|
|
44
|
+
main: Main component file path (relative to package root)
|
|
45
|
+
dependencies: Dict of package name -> version constraint
|
|
46
|
+
keywords: List of keywords for search
|
|
47
|
+
repository: Optional repository URL
|
|
48
|
+
homepage: Optional homepage URL
|
|
49
|
+
exports: List of exported component names
|
|
50
|
+
"""
|
|
51
|
+
name: str
|
|
52
|
+
version: str
|
|
53
|
+
description: str = ""
|
|
54
|
+
author: str = ""
|
|
55
|
+
license: str = "MIT"
|
|
56
|
+
main: str = "src/index.q"
|
|
57
|
+
dependencies: Dict[str, str] = field(default_factory=dict)
|
|
58
|
+
keywords: List[str] = field(default_factory=list)
|
|
59
|
+
repository: Optional[str] = None
|
|
60
|
+
homepage: Optional[str] = None
|
|
61
|
+
exports: List[str] = field(default_factory=list)
|
|
62
|
+
|
|
63
|
+
# Internal
|
|
64
|
+
_path: Optional[Path] = None
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def load(cls, manifest_path: Path) -> 'PackageManifest':
|
|
68
|
+
"""Load manifest from quantum.yaml file."""
|
|
69
|
+
if yaml is None:
|
|
70
|
+
raise ManifestError("PyYAML not installed. Install with: pip install pyyaml")
|
|
71
|
+
|
|
72
|
+
if not manifest_path.exists():
|
|
73
|
+
raise ManifestError(f"Manifest not found: {manifest_path}")
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
with open(manifest_path, 'r', encoding='utf-8') as f:
|
|
77
|
+
data = yaml.safe_load(f)
|
|
78
|
+
except yaml.YAMLError as e:
|
|
79
|
+
raise ManifestError(f"Invalid YAML in manifest: {e}")
|
|
80
|
+
|
|
81
|
+
if not data:
|
|
82
|
+
raise ManifestError("Empty manifest file")
|
|
83
|
+
|
|
84
|
+
# Validate required fields
|
|
85
|
+
if 'name' not in data:
|
|
86
|
+
raise ManifestError("Package name is required")
|
|
87
|
+
if 'version' not in data:
|
|
88
|
+
raise ManifestError("Package version is required")
|
|
89
|
+
|
|
90
|
+
# Validate name format
|
|
91
|
+
name = data['name']
|
|
92
|
+
if not cls._validate_name(name):
|
|
93
|
+
raise ManifestError(
|
|
94
|
+
f"Invalid package name: {name}. "
|
|
95
|
+
"Names must be lowercase, alphanumeric with hyphens allowed."
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Validate version format
|
|
99
|
+
version = data['version']
|
|
100
|
+
if not cls._validate_version(version):
|
|
101
|
+
raise ManifestError(
|
|
102
|
+
f"Invalid version: {version}. "
|
|
103
|
+
"Use semantic versioning (e.g., 1.0.0)"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Parse dependencies
|
|
107
|
+
dependencies = {}
|
|
108
|
+
if 'dependencies' in data and data['dependencies']:
|
|
109
|
+
for dep_name, dep_version in data['dependencies'].items():
|
|
110
|
+
if not cls._validate_name(dep_name):
|
|
111
|
+
raise ManifestError(f"Invalid dependency name: {dep_name}")
|
|
112
|
+
if not cls._validate_version_constraint(dep_version):
|
|
113
|
+
raise ManifestError(f"Invalid version constraint for {dep_name}: {dep_version}")
|
|
114
|
+
dependencies[dep_name] = dep_version
|
|
115
|
+
|
|
116
|
+
manifest = cls(
|
|
117
|
+
name=name,
|
|
118
|
+
version=str(version),
|
|
119
|
+
description=data.get('description', ''),
|
|
120
|
+
author=data.get('author', ''),
|
|
121
|
+
license=data.get('license', 'MIT'),
|
|
122
|
+
main=data.get('main', 'src/index.q'),
|
|
123
|
+
dependencies=dependencies,
|
|
124
|
+
keywords=data.get('keywords', []) or [],
|
|
125
|
+
repository=data.get('repository'),
|
|
126
|
+
homepage=data.get('homepage'),
|
|
127
|
+
exports=data.get('exports', []) or [],
|
|
128
|
+
)
|
|
129
|
+
manifest._path = manifest_path.parent
|
|
130
|
+
|
|
131
|
+
return manifest
|
|
132
|
+
|
|
133
|
+
@staticmethod
|
|
134
|
+
def _validate_name(name: str) -> bool:
|
|
135
|
+
"""Validate package name format."""
|
|
136
|
+
if not name:
|
|
137
|
+
return False
|
|
138
|
+
# lowercase, alphanumeric, hyphens allowed, must start with letter
|
|
139
|
+
pattern = r'^[a-z][a-z0-9-]*$'
|
|
140
|
+
return bool(re.match(pattern, name))
|
|
141
|
+
|
|
142
|
+
@staticmethod
|
|
143
|
+
def _validate_version(version: str) -> bool:
|
|
144
|
+
"""Validate semantic version format."""
|
|
145
|
+
if not version:
|
|
146
|
+
return False
|
|
147
|
+
# Basic semver: major.minor.patch with optional prerelease
|
|
148
|
+
pattern = r'^\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$'
|
|
149
|
+
return bool(re.match(pattern, str(version)))
|
|
150
|
+
|
|
151
|
+
@staticmethod
|
|
152
|
+
def _validate_version_constraint(constraint: str) -> bool:
|
|
153
|
+
"""Validate version constraint format."""
|
|
154
|
+
if not constraint:
|
|
155
|
+
return False
|
|
156
|
+
# Support: exact, ^, ~, >=, >, <=, <, or ranges
|
|
157
|
+
patterns = [
|
|
158
|
+
r'^\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$', # exact: 1.0.0
|
|
159
|
+
r'^\^?\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$', # caret: ^1.0.0
|
|
160
|
+
r'^~\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$', # tilde: ~1.0.0
|
|
161
|
+
r'^[><]=?\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$', # comparison: >=1.0.0
|
|
162
|
+
r'^\*$', # any version
|
|
163
|
+
]
|
|
164
|
+
return any(re.match(p, str(constraint)) for p in patterns)
|
|
165
|
+
|
|
166
|
+
def save(self, path: Optional[Path] = None) -> None:
|
|
167
|
+
"""Save manifest to quantum.yaml file."""
|
|
168
|
+
if yaml is None:
|
|
169
|
+
raise ManifestError("PyYAML not installed. Install with: pip install pyyaml")
|
|
170
|
+
|
|
171
|
+
target_path = path or (self._path / 'quantum.yaml' if self._path else None)
|
|
172
|
+
if not target_path:
|
|
173
|
+
raise ManifestError("No path specified for saving manifest")
|
|
174
|
+
|
|
175
|
+
if isinstance(target_path, Path) and target_path.is_dir():
|
|
176
|
+
target_path = target_path / 'quantum.yaml'
|
|
177
|
+
|
|
178
|
+
data = {
|
|
179
|
+
'name': self.name,
|
|
180
|
+
'version': self.version,
|
|
181
|
+
'description': self.description,
|
|
182
|
+
'author': self.author,
|
|
183
|
+
'license': self.license,
|
|
184
|
+
'main': self.main,
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if self.dependencies:
|
|
188
|
+
data['dependencies'] = self.dependencies
|
|
189
|
+
|
|
190
|
+
if self.keywords:
|
|
191
|
+
data['keywords'] = self.keywords
|
|
192
|
+
|
|
193
|
+
if self.repository:
|
|
194
|
+
data['repository'] = self.repository
|
|
195
|
+
|
|
196
|
+
if self.homepage:
|
|
197
|
+
data['homepage'] = self.homepage
|
|
198
|
+
|
|
199
|
+
if self.exports:
|
|
200
|
+
data['exports'] = self.exports
|
|
201
|
+
|
|
202
|
+
with open(target_path, 'w', encoding='utf-8') as f:
|
|
203
|
+
yaml.dump(data, f, default_flow_style=False, sort_keys=False, allow_unicode=True)
|
|
204
|
+
|
|
205
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
206
|
+
"""Convert manifest to dictionary."""
|
|
207
|
+
return {
|
|
208
|
+
'name': self.name,
|
|
209
|
+
'version': self.version,
|
|
210
|
+
'description': self.description,
|
|
211
|
+
'author': self.author,
|
|
212
|
+
'license': self.license,
|
|
213
|
+
'main': self.main,
|
|
214
|
+
'dependencies': self.dependencies,
|
|
215
|
+
'keywords': self.keywords,
|
|
216
|
+
'repository': self.repository,
|
|
217
|
+
'homepage': self.homepage,
|
|
218
|
+
'exports': self.exports,
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
def get_main_component_path(self) -> Path:
|
|
222
|
+
"""Get absolute path to main component file."""
|
|
223
|
+
if not self._path:
|
|
224
|
+
raise ManifestError("Package path not set")
|
|
225
|
+
return self._path / self.main
|
|
226
|
+
|
|
227
|
+
def get_component_paths(self) -> List[Path]:
|
|
228
|
+
"""Get all component (.q) files in the package."""
|
|
229
|
+
if not self._path:
|
|
230
|
+
raise ManifestError("Package path not set")
|
|
231
|
+
|
|
232
|
+
components = []
|
|
233
|
+
src_dir = self._path / 'src'
|
|
234
|
+
if src_dir.exists():
|
|
235
|
+
for qfile in src_dir.rglob('*.q'):
|
|
236
|
+
components.append(qfile)
|
|
237
|
+
|
|
238
|
+
# Also check root if main is at root level
|
|
239
|
+
main_path = self.get_main_component_path()
|
|
240
|
+
if main_path.exists() and main_path not in components:
|
|
241
|
+
components.append(main_path)
|
|
242
|
+
|
|
243
|
+
return components
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def init_package(
|
|
247
|
+
path: Path,
|
|
248
|
+
name: Optional[str] = None,
|
|
249
|
+
description: str = "",
|
|
250
|
+
author: str = "",
|
|
251
|
+
license_id: str = "MIT"
|
|
252
|
+
) -> PackageManifest:
|
|
253
|
+
"""
|
|
254
|
+
Initialize a new package in the given directory.
|
|
255
|
+
|
|
256
|
+
Creates:
|
|
257
|
+
- quantum.yaml manifest
|
|
258
|
+
- src/ directory with index.q
|
|
259
|
+
- examples/ directory
|
|
260
|
+
- README.md
|
|
261
|
+
"""
|
|
262
|
+
if yaml is None:
|
|
263
|
+
raise ManifestError("PyYAML not installed. Install with: pip install pyyaml")
|
|
264
|
+
|
|
265
|
+
path = Path(path)
|
|
266
|
+
|
|
267
|
+
# Use directory name as package name if not provided
|
|
268
|
+
if not name:
|
|
269
|
+
name = path.name.lower().replace('_', '-').replace(' ', '-')
|
|
270
|
+
# Remove invalid characters
|
|
271
|
+
name = re.sub(r'[^a-z0-9-]', '', name)
|
|
272
|
+
if not name or not name[0].isalpha():
|
|
273
|
+
name = 'my-component'
|
|
274
|
+
|
|
275
|
+
# Create directories
|
|
276
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
277
|
+
(path / 'src').mkdir(exist_ok=True)
|
|
278
|
+
(path / 'examples').mkdir(exist_ok=True)
|
|
279
|
+
|
|
280
|
+
# Create manifest
|
|
281
|
+
manifest = PackageManifest(
|
|
282
|
+
name=name,
|
|
283
|
+
version='1.0.0',
|
|
284
|
+
description=description,
|
|
285
|
+
author=author,
|
|
286
|
+
license=license_id,
|
|
287
|
+
main='src/index.q',
|
|
288
|
+
)
|
|
289
|
+
manifest._path = path
|
|
290
|
+
manifest.save()
|
|
291
|
+
|
|
292
|
+
# Create main component file
|
|
293
|
+
component_name = ''.join(word.capitalize() for word in name.split('-'))
|
|
294
|
+
main_content = f'''<q:component name="{component_name}">
|
|
295
|
+
<!-- Component parameters -->
|
|
296
|
+
<q:param name="title" type="string" default="{component_name}" />
|
|
297
|
+
|
|
298
|
+
<!-- Component template -->
|
|
299
|
+
<div class="{name}">
|
|
300
|
+
<h1>{{title}}</h1>
|
|
301
|
+
<q:slot />
|
|
302
|
+
</div>
|
|
303
|
+
</q:component>
|
|
304
|
+
'''
|
|
305
|
+
|
|
306
|
+
with open(path / 'src' / 'index.q', 'w', encoding='utf-8') as f:
|
|
307
|
+
f.write(main_content)
|
|
308
|
+
|
|
309
|
+
# Create example file
|
|
310
|
+
example_content = f'''<q:component name="Demo">
|
|
311
|
+
<q:import component="{component_name}" from="../src" />
|
|
312
|
+
|
|
313
|
+
<{component_name} title="Hello World">
|
|
314
|
+
<p>This is a demo of the {name} component.</p>
|
|
315
|
+
</{component_name}>
|
|
316
|
+
</q:component>
|
|
317
|
+
'''
|
|
318
|
+
|
|
319
|
+
with open(path / 'examples' / 'demo.q', 'w', encoding='utf-8') as f:
|
|
320
|
+
f.write(example_content)
|
|
321
|
+
|
|
322
|
+
# Create README
|
|
323
|
+
readme_content = f'''# {name}
|
|
324
|
+
|
|
325
|
+
{description or 'A Quantum component package.'}
|
|
326
|
+
|
|
327
|
+
## Installation
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
quantum pkg install {name}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## Usage
|
|
334
|
+
|
|
335
|
+
```xml
|
|
336
|
+
<q:import component="{component_name}" from="{name}" />
|
|
337
|
+
|
|
338
|
+
<{component_name} title="Example">
|
|
339
|
+
<p>Content goes here</p>
|
|
340
|
+
</{component_name}>
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
## License
|
|
344
|
+
|
|
345
|
+
{license_id}
|
|
346
|
+
'''
|
|
347
|
+
|
|
348
|
+
with open(path / 'README.md', 'w', encoding='utf-8') as f:
|
|
349
|
+
f.write(readme_content)
|
|
350
|
+
|
|
351
|
+
return manifest
|