jac-client 0.2.6__py3-none-any.whl → 0.2.11__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 (119) hide show
  1. jac_client/examples/all-in-one/{src/button.jac → button.jac} +4 -3
  2. jac_client/examples/all-in-one/components/CategoryFilter.jac +47 -0
  3. jac_client/examples/all-in-one/components/Header.jac +17 -0
  4. jac_client/examples/all-in-one/components/ProfitOverview.jac +64 -0
  5. jac_client/examples/all-in-one/components/Summary.jac +76 -0
  6. jac_client/examples/all-in-one/components/TransactionForm.jac +188 -0
  7. jac_client/examples/all-in-one/components/TransactionItem.jac +62 -0
  8. jac_client/examples/all-in-one/components/TransactionList.jac +44 -0
  9. jac_client/examples/all-in-one/components/button.jac +8 -0
  10. jac_client/examples/all-in-one/components/navigation.jac +126 -0
  11. jac_client/examples/all-in-one/constants/categories.jac +36 -0
  12. jac_client/examples/all-in-one/constants/clients.jac +12 -0
  13. jac_client/examples/all-in-one/context/BudgetContext.jac +31 -0
  14. jac_client/examples/all-in-one/hooks/useBudget.jac +122 -0
  15. jac_client/examples/all-in-one/hooks/useLocalStorage.jac +37 -0
  16. jac_client/examples/all-in-one/main.jac +542 -0
  17. jac_client/examples/all-in-one/pages/BudgetPlanner.jac +140 -0
  18. jac_client/examples/all-in-one/pages/FeaturesTest.jac +157 -0
  19. jac_client/examples/all-in-one/pages/LandingPage.jac +124 -0
  20. jac_client/examples/all-in-one/pages/budget_planner_ui.cl.jac +65 -0
  21. jac_client/examples/all-in-one/pages/features_test_ui.cl.jac +675 -0
  22. jac_client/examples/all-in-one/pages/loginPage.jac +127 -0
  23. jac_client/examples/all-in-one/pages/nestedDemo.jac +54 -0
  24. jac_client/examples/all-in-one/pages/notFound.jac +18 -0
  25. jac_client/examples/all-in-one/pages/signupPage.jac +127 -0
  26. jac_client/examples/all-in-one/utils/formatters.jac +49 -0
  27. jac_client/examples/asset-serving/css-with-image/main.jac +92 -0
  28. jac_client/examples/asset-serving/image-asset/main.jac +56 -0
  29. jac_client/examples/asset-serving/import-alias/main.jac +109 -0
  30. jac_client/examples/basic/main.jac +23 -0
  31. jac_client/examples/basic-auth/main.jac +363 -0
  32. jac_client/examples/basic-auth-with-router/main.jac +451 -0
  33. jac_client/examples/basic-full-stack/main.jac +362 -0
  34. jac_client/examples/css-styling/js-styling/main.jac +63 -0
  35. jac_client/examples/css-styling/material-ui/main.jac +122 -0
  36. jac_client/examples/css-styling/pure-css/main.jac +55 -0
  37. jac_client/examples/css-styling/sass-example/main.jac +55 -0
  38. jac_client/examples/css-styling/styled-components/main.jac +62 -0
  39. jac_client/examples/css-styling/tailwind-example/main.jac +74 -0
  40. jac_client/examples/full-stack-with-auth/main.jac +696 -0
  41. jac_client/examples/little-x/main.jac +681 -0
  42. jac_client/examples/little-x/src/submit-button.jac +15 -14
  43. jac_client/examples/nested-folders/nested-advance/main.jac +26 -0
  44. jac_client/examples/nested-folders/nested-advance/src/ButtonRoot.jac +4 -6
  45. jac_client/examples/nested-folders/nested-advance/src/level1/ButtonSecondL.jac +9 -13
  46. jac_client/examples/nested-folders/nested-advance/src/level1/Card.jac +29 -32
  47. jac_client/examples/nested-folders/nested-advance/src/level1/level2/ButtonThirdL.jac +12 -18
  48. jac_client/examples/nested-folders/nested-basic/{src/app.jac → main.jac} +7 -5
  49. jac_client/examples/nested-folders/nested-basic/src/button.jac +4 -3
  50. jac_client/examples/nested-folders/nested-basic/src/components/button.jac +4 -3
  51. jac_client/examples/ts-support/main.jac +35 -0
  52. jac_client/examples/with-router/main.jac +286 -0
  53. jac_client/plugin/cli.jac +507 -470
  54. jac_client/plugin/client.jac +30 -12
  55. jac_client/plugin/client_runtime.cl.jac +25 -15
  56. jac_client/plugin/impl/client.impl.jac +126 -26
  57. jac_client/plugin/impl/client_runtime.impl.jac +182 -10
  58. jac_client/plugin/plugin_config.jac +216 -34
  59. jac_client/plugin/src/__init__.jac +0 -2
  60. jac_client/plugin/src/compiler.jac +2 -2
  61. jac_client/plugin/src/config_loader.jac +1 -0
  62. jac_client/plugin/src/desktop_config.jac +31 -0
  63. jac_client/plugin/src/impl/compiler.impl.jac +99 -30
  64. jac_client/plugin/src/impl/config_loader.impl.jac +8 -0
  65. jac_client/plugin/src/impl/desktop_config.impl.jac +191 -0
  66. jac_client/plugin/src/impl/jac_to_js.impl.jac +5 -1
  67. jac_client/plugin/src/impl/package_installer.impl.jac +20 -20
  68. jac_client/plugin/src/impl/vite_bundler.impl.jac +384 -144
  69. jac_client/plugin/src/package_installer.jac +1 -1
  70. jac_client/plugin/src/targets/desktop/sidecar/main.py +144 -0
  71. jac_client/plugin/src/targets/desktop_target.jac +37 -0
  72. jac_client/plugin/src/targets/impl/desktop_target.impl.jac +2347 -0
  73. jac_client/plugin/src/targets/impl/registry.impl.jac +64 -0
  74. jac_client/plugin/src/targets/impl/web_target.impl.jac +157 -0
  75. jac_client/plugin/src/targets/register.jac +21 -0
  76. jac_client/plugin/src/targets/registry.jac +87 -0
  77. jac_client/plugin/src/targets/web_target.jac +35 -0
  78. jac_client/plugin/src/vite_bundler.jac +15 -1
  79. jac_client/plugin/utils/__init__.jac +3 -0
  80. jac_client/plugin/utils/bun_installer.jac +16 -0
  81. jac_client/plugin/utils/impl/bun_installer.impl.jac +99 -0
  82. jac_client/templates/client.jacpack +72 -0
  83. jac_client/templates/fullstack.jacpack +61 -0
  84. jac_client/tests/conftest.py +110 -52
  85. jac_client/tests/fixtures/spawn_test/app.jac +64 -70
  86. jac_client/tests/fixtures/with-ts/app.jac +28 -28
  87. jac_client/tests/test_cli.py +280 -113
  88. jac_client/tests/test_e2e.py +232 -0
  89. jac_client/tests/test_helpers.py +58 -0
  90. jac_client/tests/test_it.py +325 -154
  91. jac_client/tests/test_it_desktop.py +891 -0
  92. {jac_client-0.2.6.dist-info → jac_client-0.2.11.dist-info}/METADATA +20 -11
  93. jac_client-0.2.11.dist-info/RECORD +113 -0
  94. {jac_client-0.2.6.dist-info → jac_client-0.2.11.dist-info}/WHEEL +1 -1
  95. jac_client/examples/all-in-one/src/app.jac +0 -841
  96. jac_client/examples/all-in-one/src/components/button.jac +0 -7
  97. jac_client/examples/asset-serving/css-with-image/src/app.jac +0 -88
  98. jac_client/examples/asset-serving/image-asset/src/app.jac +0 -55
  99. jac_client/examples/asset-serving/import-alias/src/app.jac +0 -111
  100. jac_client/examples/basic/src/app.jac +0 -21
  101. jac_client/examples/basic-auth/src/app.jac +0 -377
  102. jac_client/examples/basic-auth-with-router/src/app.jac +0 -464
  103. jac_client/examples/basic-full-stack/src/app.jac +0 -365
  104. jac_client/examples/css-styling/js-styling/src/app.jac +0 -84
  105. jac_client/examples/css-styling/material-ui/src/app.jac +0 -122
  106. jac_client/examples/css-styling/pure-css/src/app.jac +0 -64
  107. jac_client/examples/css-styling/sass-example/src/app.jac +0 -64
  108. jac_client/examples/css-styling/styled-components/src/app.jac +0 -71
  109. jac_client/examples/css-styling/tailwind-example/src/app.jac +0 -63
  110. jac_client/examples/full-stack-with-auth/src/app.jac +0 -722
  111. jac_client/examples/little-x/src/app.jac +0 -719
  112. jac_client/examples/nested-folders/nested-advance/src/app.jac +0 -35
  113. jac_client/examples/ts-support/src/app.jac +0 -35
  114. jac_client/examples/with-router/src/app.jac +0 -323
  115. jac_client/plugin/src/babel_processor.jac +0 -18
  116. jac_client/plugin/src/impl/babel_processor.impl.jac +0 -84
  117. jac_client-0.2.6.dist-info/RECORD +0 -74
  118. {jac_client-0.2.6.dist-info → jac_client-0.2.11.dist-info}/entry_points.txt +0 -0
  119. {jac_client-0.2.6.dist-info → jac_client-0.2.11.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,191 @@
1
+ """Implementation of Desktop target configuration loader."""
2
+ import from pathlib { Path }
3
+ import from typing { Any }
4
+ import from jaclang.project.config { JacConfig, get_config }
5
+ import from jaclang.project.plugin_config { deep_merge }
6
+ import from jaclang.cli.console { console }
7
+
8
+ """Initialize DesktopConfig with project directory."""
9
+ impl DesktopConfig.init(self: DesktopConfig, project_dir: Path | None = None) -> None {
10
+ if project_dir is None {
11
+ self.project_dir = Path.cwd();
12
+ } else {
13
+ self.project_dir = project_dir;
14
+ }
15
+ self._config = None;
16
+ self._jac_config = None;
17
+ }
18
+
19
+ """Get default configuration structure for desktop target."""
20
+ impl DesktopConfig.get_default_config(self: DesktopConfig) -> dict[str, Any] {
21
+ # Try to get project name/version from JacConfig for defaults
22
+ # If config is not available, use fallback defaults
23
+ project_name = "my-jac-app";
24
+ project_version = "1.0.0";
25
+ try {
26
+ jac_config = self._get_jac_config();
27
+ if jac_config and jac_config.project {
28
+ project_name = jac_config.project.name or project_name;
29
+ project_version = jac_config.project.version or project_version;
30
+ }
31
+ } except Exception {
32
+ # If config loading fails, use defaults
33
+ console.warning("Failed to load JacConfig, using fallback defaults");
34
+ }
35
+ # Generate identifier from project name
36
+ identifier = _generate_identifier(project_name);
37
+ return {
38
+ 'name': project_name,
39
+ 'identifier': identifier,
40
+ 'version': project_version,
41
+ 'window': {
42
+ 'title': project_name,
43
+ 'width': 1200,
44
+ 'height': 800,
45
+ 'min_width': 800,
46
+ 'min_height': 600,
47
+ 'resizable': True,
48
+ 'fullscreen': False
49
+ },
50
+ 'platforms': {'windows': True, 'macos': True, 'linux': True},
51
+ 'features': {
52
+ 'system_tray': False,
53
+ 'auto_update': False,
54
+ 'notifications': False
55
+ }
56
+ };
57
+ }
58
+
59
+ """Get or load the core JacConfig instance."""
60
+ impl DesktopConfig._get_jac_config(self: DesktopConfig) -> JacConfig {
61
+ if self._jac_config is None {
62
+ self._jac_config = get_config();
63
+ if self._jac_config is None {
64
+ raise RuntimeError(
65
+ "No jac.toml found. Run 'jac create' to create a project."
66
+ ) ;
67
+ }
68
+ }
69
+ return self._jac_config;
70
+ }
71
+
72
+ """Load configuration from jac.toml, merging with defaults."""
73
+ impl DesktopConfig.load(self: DesktopConfig) -> dict[str, Any] {
74
+ if self._config is not None {
75
+ return self._config;
76
+ }
77
+ default_config = self.get_default_config();
78
+ # Try to get [desktop] section from jac.toml
79
+ desktop_config = {};
80
+ try {
81
+ jac_config = self._get_jac_config();
82
+ # Get [desktop] section from raw TOML data
83
+ # The [desktop] section is not under [plugins], so we access it directly
84
+ if jac_config and jac_config._raw_data {
85
+ raw_data = jac_config._raw_data;
86
+ desktop_config = raw_data.get('desktop', {});
87
+ }
88
+ } except Exception {
89
+ # If config loading fails, use defaults only
90
+ console.warning("Failed to load JacConfig, using fallback defaults");
91
+ }
92
+ # Deep merge defaults with user configuration
93
+ if desktop_config {
94
+ self._config = deep_merge(default_config, desktop_config);
95
+ } else {
96
+ self._config = default_config;
97
+ }
98
+ return self._config;
99
+ }
100
+
101
+ """Get desktop configuration (name, identifier, version)."""
102
+ impl DesktopConfig.get_desktop_config(self: DesktopConfig) -> dict[str, Any] {
103
+ config = self.load();
104
+ return {
105
+ 'name': config.get('name', ''),
106
+ 'identifier': config.get('identifier', ''),
107
+ 'version': config.get('version', '1.0.0')
108
+ };
109
+ }
110
+
111
+ """Get window configuration."""
112
+ impl DesktopConfig.get_window_config(self: DesktopConfig) -> dict[str, Any] {
113
+ config = self.load();
114
+ return config.get('window', {});
115
+ }
116
+
117
+ """Get platforms configuration."""
118
+ impl DesktopConfig.get_platforms_config(self: DesktopConfig) -> dict[str, Any] {
119
+ config = self.load();
120
+ return config.get('platforms', {});
121
+ }
122
+
123
+ """Get features configuration."""
124
+ impl DesktopConfig.get_features_config(self: DesktopConfig) -> dict[str, Any] {
125
+ config = self.load();
126
+ return config.get('features', {});
127
+ }
128
+
129
+ """Validate desktop configuration."""
130
+ impl DesktopConfig.validate(self: DesktopConfig) -> None {
131
+ config = self.load();
132
+ # Required fields
133
+ name = config.get('name', '');
134
+ if not name {
135
+ raise ValueError(
136
+ "Desktop configuration error: 'name' is required in [desktop] section"
137
+ ) ;
138
+ }
139
+ identifier = config.get('identifier', '');
140
+ if not identifier {
141
+ raise ValueError(
142
+ "Desktop configuration error: 'identifier' is required in [desktop] section"
143
+ ) ;
144
+ }
145
+ # Validate identifier format (should be reverse domain notation)
146
+ if not _is_valid_identifier(identifier) {
147
+ console.warning(
148
+ f"Desktop identifier '{identifier}' may not be valid. Use reverse domain notation (e.g., 'com.example.myapp')"
149
+ );
150
+ }
151
+ # Validate window dimensions
152
+ window = config.get('window', {});
153
+ width = window.get('width', 1200);
154
+ height = window.get('height', 800);
155
+ min_width = window.get('min_width', 800);
156
+ min_height = window.get('min_height', 600);
157
+ if min_width > width {
158
+ raise ValueError(
159
+ f"Desktop configuration error: window.min_width ({min_width}) cannot be greater than window.width ({width})"
160
+ ) ;
161
+ }
162
+ if min_height > height {
163
+ raise ValueError(
164
+ f"Desktop configuration error: window.min_height ({min_height}) cannot be greater than window.height ({height})"
165
+ ) ;
166
+ }
167
+ }
168
+
169
+ """Generate identifier from project name."""
170
+ def _generate_identifier(name: str) -> str {
171
+ # Convert to lowercase, replace spaces/special chars with dots
172
+ import re;
173
+ # Remove special characters, keep alphanumeric, dots, hyphens
174
+ cleaned = re.sub(r'[^a-zA-Z0-9.\-]', '', name.lower());
175
+ # Replace multiple dots/hyphens with single dot
176
+ cleaned = re.sub(r'[.\-]+', '.', cleaned);
177
+ # Remove leading/trailing dots
178
+ cleaned = cleaned.strip('.');
179
+ # If empty or doesn't look like reverse domain, prefix with 'com.'
180
+ if not cleaned or not '.' in cleaned {
181
+ cleaned = f"com.{cleaned}" if cleaned else "com.myapp";
182
+ }
183
+ return cleaned;
184
+ }
185
+
186
+ """Check if identifier is valid (reverse domain notation)."""
187
+ def _is_valid_identifier(identifier: str) -> bool {
188
+ import re;
189
+ # Should be like: com.example.myapp (at least one dot, alphanumeric + dots)
190
+ return bool(re.match(r'^[a-z0-9]+(\.[a-z0-9]+)+$', identifier.lower()));
191
+ }
@@ -1,7 +1,11 @@
1
1
  """Add runtime imports to compiled JS code."""
2
2
 
3
3
  impl JacToJSCompiler.add_runtime_imports(self: JacToJSCompiler, js_code: str) -> str {
4
- jac_jsx_import = 'import {__jacJsx, __jacSpawn} from "@jac-client/utils";';
4
+ # Skip adding import if this file IS the runtime (defines __jacJsx itself)
5
+ if "function __jacJsx(" in js_code {
6
+ return js_code;
7
+ }
8
+ jac_jsx_import = 'import {__jacJsx, __jacSpawn} from "@jac/runtime";';
5
9
  return f"{jac_jsx_import}\n{js_code}";
6
10
  }
7
11
 
@@ -33,39 +33,39 @@ impl PackageInstaller.uninstall_package(
33
33
  }
34
34
  # Save the updated config
35
35
  self.config_loader.save();
36
- # Regenerate package.json and run npm install to actually remove the package
36
+ # Regenerate package.json and run bun install to actually remove the package
37
37
  self._regenerate_and_install();
38
38
  }
39
39
 
40
- """Regenerate package.json from jac.toml and run npm install."""
40
+ """Regenerate package.json from jac.toml and run bun install."""
41
41
  impl PackageInstaller._regenerate_and_install(self: PackageInstaller) -> None {
42
+ import from jac_client.plugin.utils { ensure_bun_available }
43
+ # Ensure bun is available before proceeding
44
+ if not ensure_bun_available() {
45
+ raise ClientBundleError('Bun is required. Install manually: https://bun.sh') from None ;
46
+ }
42
47
  # Regenerate package.json from updated jac.toml
43
48
  bundler = ViteBundler(self.project_dir);
44
49
  bundler.create_package_json();
45
- # Ensure root package.json exists temporarily for npm commands
50
+ # Ensure root package.json exists temporarily for bun commands
46
51
  bundler._ensure_root_package_json();
47
52
  try {
48
- # Run npm install to actually install the packages
49
- subprocess.run(
50
- ['npm', 'install'],
51
- cwd=self.project_dir,
52
- check=True,
53
- capture_output=True,
54
- text=True
53
+ # Run bun install to actually install the packages
54
+ print("\n ⏳ Installing packages...\n", flush=True);
55
+ result = subprocess.run(
56
+ ['bun', 'install'], cwd=self.project_dir, check=False, text=True
55
57
  );
56
- } except subprocess.CalledProcessError as e {
57
- raise ClientBundleError(f'Failed to install npm packages: {e.stderr}') from e ;
58
- } except FileNotFoundError {
59
- raise ClientBundleError(
60
- 'npm command not found. Ensure Node.js and npm are installed.'
61
- ) from None ;
58
+ if result.returncode != 0 {
59
+ raise ClientBundleError('Failed to install packages (see output above)') ;
60
+ }
61
+ print("\n ✔ Packages installed", flush=True);
62
62
  } finally {
63
- # Always clean up root package.json and move package-lock.json
63
+ # Always clean up root package.json and move bun.lockb
64
64
  bundler._cleanup_root_package_files();
65
65
  }
66
66
  }
67
67
 
68
- """Install all packages from jac.toml (regenerate package.json and run npm install)."""
68
+ """Install all packages from jac.toml (regenerate package.json and run bun install)."""
69
69
  impl PackageInstaller.install_all(self: PackageInstaller) -> None {
70
70
  if not self.config_file.exists() {
71
71
  raise ClientBundleError(
@@ -93,11 +93,11 @@ impl PackageInstaller.install_package(
93
93
  self.config_loader.add_dependency(package_name, package_version, is_dev);
94
94
  # Save the updated config
95
95
  self.config_loader.save();
96
- # Regenerate package.json and install the package via npm
96
+ # Regenerate package.json and install the package via bun
97
97
  self._regenerate_and_install();
98
98
  }
99
99
 
100
- """Handles installing npm packages by updating jac.toml."""
100
+ """Handles installing packages by updating jac.toml."""
101
101
  impl PackageInstaller.init(self: PackageInstaller, project_dir: Path) {
102
102
  self.project_dir = project_dir;
103
103
  self.config_loader = JacClientConfig(project_dir);