jac-client 0.2.5__py3-none-any.whl → 0.2.7__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.
- jac_client/examples/all-in-one/src/app.jac +473 -741
- jac_client/examples/all-in-one/src/components/CategoryFilter.jac +35 -0
- jac_client/examples/all-in-one/src/components/Header.jac +13 -0
- jac_client/examples/all-in-one/src/components/ProfitOverview.jac +50 -0
- jac_client/examples/all-in-one/src/components/Summary.jac +53 -0
- jac_client/examples/all-in-one/src/components/TransactionForm.jac +158 -0
- jac_client/examples/all-in-one/src/components/TransactionItem.jac +55 -0
- jac_client/examples/all-in-one/src/components/TransactionList.jac +37 -0
- jac_client/examples/all-in-one/src/components/navigation.jac +132 -0
- jac_client/examples/all-in-one/src/constants/categories.jac +37 -0
- jac_client/examples/all-in-one/src/constants/clients.jac +13 -0
- jac_client/examples/all-in-one/src/context/BudgetContext.jac +28 -0
- jac_client/examples/all-in-one/src/hooks/useBudget.jac +116 -0
- jac_client/examples/all-in-one/src/hooks/useLocalStorage.jac +36 -0
- jac_client/examples/all-in-one/src/pages/BudgetPlanner.cl.jac +70 -0
- jac_client/examples/all-in-one/src/pages/BudgetPlanner.jac +126 -0
- jac_client/examples/all-in-one/src/pages/FeaturesTest.cl.jac +552 -0
- jac_client/examples/all-in-one/src/pages/FeaturesTest.jac +126 -0
- jac_client/examples/all-in-one/src/pages/LandingPage.jac +101 -0
- jac_client/examples/all-in-one/src/pages/loginPage.jac +132 -0
- jac_client/examples/all-in-one/src/pages/nestedDemo.jac +61 -0
- jac_client/examples/all-in-one/src/pages/notFound.jac +24 -0
- jac_client/examples/all-in-one/src/pages/signupPage.jac +133 -0
- jac_client/examples/all-in-one/src/utils/formatters.jac +52 -0
- jac_client/examples/asset-serving/css-with-image/src/app.jac +3 -3
- jac_client/examples/asset-serving/image-asset/src/app.jac +3 -3
- jac_client/examples/asset-serving/import-alias/src/app.jac +3 -3
- jac_client/examples/basic/src/app.jac +3 -3
- jac_client/examples/basic-auth/src/app.jac +31 -37
- jac_client/examples/basic-auth-with-router/src/app.jac +16 -16
- jac_client/examples/basic-full-stack/src/app.jac +24 -30
- jac_client/examples/css-styling/js-styling/src/app.jac +5 -5
- jac_client/examples/css-styling/material-ui/src/app.jac +5 -5
- jac_client/examples/css-styling/pure-css/src/app.jac +5 -5
- jac_client/examples/css-styling/sass-example/src/app.jac +5 -5
- jac_client/examples/css-styling/styled-components/src/app.jac +5 -5
- jac_client/examples/css-styling/tailwind-example/src/app.jac +5 -5
- jac_client/examples/full-stack-with-auth/src/app.jac +16 -16
- jac_client/examples/ts-support/src/app.jac +4 -4
- jac_client/examples/with-router/src/app.jac +4 -4
- jac_client/plugin/cli.jac +155 -203
- jac_client/plugin/client_runtime.cl.jac +5 -1
- jac_client/plugin/impl/client.impl.jac +74 -12
- jac_client/plugin/plugin_config.jac +11 -11
- jac_client/plugin/src/compiler.jac +2 -1
- jac_client/plugin/src/impl/babel_processor.impl.jac +22 -17
- jac_client/plugin/src/impl/compiler.impl.jac +57 -18
- jac_client/plugin/src/impl/vite_bundler.impl.jac +66 -102
- jac_client/plugin/src/package_installer.jac +1 -1
- jac_client/plugin/src/vite_bundler.jac +1 -0
- jac_client/tests/conftest.py +10 -8
- jac_client/tests/fixtures/spawn_test/app.jac +15 -18
- jac_client/tests/fixtures/with-ts/app.jac +4 -4
- jac_client/tests/test_cli.py +99 -45
- jac_client/tests/test_it.py +290 -79
- {jac_client-0.2.5.dist-info → jac_client-0.2.7.dist-info}/METADATA +16 -7
- jac_client-0.2.7.dist-info/RECORD +97 -0
- jac_client-0.2.5.dist-info/RECORD +0 -74
- {jac_client-0.2.5.dist-info → jac_client-0.2.7.dist-info}/WHEEL +0 -0
- {jac_client-0.2.5.dist-info → jac_client-0.2.7.dist-info}/entry_points.txt +0 -0
- {jac_client-0.2.5.dist-info → jac_client-0.2.7.dist-info}/top_level.txt +0 -0
jac_client/plugin/cli.jac
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Command line interface tool for the Jac Client.
|
|
2
2
|
|
|
3
3
|
This module extends the core `create` command to add client-side (frontend)
|
|
4
|
-
project setup via the --cl flag.
|
|
4
|
+
project setup via the --cl flag using the extend_command API.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import os;
|
|
@@ -10,112 +10,82 @@ import sys;
|
|
|
10
10
|
import pathlib;
|
|
11
11
|
import subprocess;
|
|
12
12
|
import shutil;
|
|
13
|
-
import from jaclang.cli.
|
|
13
|
+
import from jaclang.cli.registry { get_registry }
|
|
14
|
+
import from jaclang.cli.command { Arg, ArgKind, HookContext }
|
|
14
15
|
import from jaclang.pycore.runtime { hookimpl }
|
|
15
|
-
import from jaclang.project.config {
|
|
16
|
+
import from jaclang.project.config { find_project_root }
|
|
16
17
|
|
|
17
18
|
"""Jac CLI extensions for client-side development."""
|
|
18
19
|
class JacCmd {
|
|
19
20
|
"""Create Jac CLI cmds."""
|
|
20
21
|
@hookimpl
|
|
21
22
|
static def create_cmd -> None {
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
_create_client_project(cwd, name, force, skip, verbose);
|
|
55
|
-
} else {
|
|
56
|
-
_create_core_project(cwd, name, force);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
# Register with PLUGIN priority to override core's create command
|
|
61
|
-
cmd_registry.register(
|
|
62
|
-
create, priority=CommandPriority.PLUGIN, source="jac-client"
|
|
23
|
+
"""Extend core create command to add --cl flag for client-side setup.""";
|
|
24
|
+
registry = get_registry();
|
|
25
|
+
|
|
26
|
+
# Extend the core 'create' command with client-specific arguments
|
|
27
|
+
registry.extend_command(
|
|
28
|
+
command_name="create",
|
|
29
|
+
args=[
|
|
30
|
+
Arg.create(
|
|
31
|
+
"cl",
|
|
32
|
+
typ=bool,
|
|
33
|
+
default=False,
|
|
34
|
+
help="Include client-side (frontend) setup",
|
|
35
|
+
short="c"
|
|
36
|
+
),
|
|
37
|
+
Arg.create(
|
|
38
|
+
"skip",
|
|
39
|
+
typ=bool,
|
|
40
|
+
default=False,
|
|
41
|
+
help="Skip installing default packages (only for --cl)",
|
|
42
|
+
short="s"
|
|
43
|
+
),
|
|
44
|
+
Arg.create(
|
|
45
|
+
"verbose",
|
|
46
|
+
typ=bool,
|
|
47
|
+
default=False,
|
|
48
|
+
help="Show detailed output during installation",
|
|
49
|
+
short="v"
|
|
50
|
+
),
|
|
51
|
+
|
|
52
|
+
],
|
|
53
|
+
pre_hook=_handle_client_create,
|
|
54
|
+
source="jac-client"
|
|
63
55
|
);
|
|
64
56
|
}
|
|
65
57
|
}
|
|
66
58
|
|
|
67
|
-
"""
|
|
68
|
-
def
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
<>exit(1);
|
|
59
|
+
"""Pre-hook to handle --cl flag for client-side project creation."""
|
|
60
|
+
def _handle_client_create(ctx: HookContext) -> None {
|
|
61
|
+
# Check if --cl flag is set
|
|
62
|
+
cl_flag = ctx.get_arg("cl", False);
|
|
63
|
+
if not cl_flag {
|
|
64
|
+
# Let core create command run normally
|
|
65
|
+
return;
|
|
75
66
|
}
|
|
76
67
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
toml_content = JacConfig.create_default_toml(project_name);
|
|
86
|
-
with open(toml_path, "w") as f {
|
|
87
|
-
f.write(toml_content);
|
|
88
|
-
}
|
|
89
|
-
print(f"Created {toml_path}");
|
|
90
|
-
|
|
91
|
-
main_jac = cwd / f"{name}.jac";
|
|
92
|
-
if not main_jac.exists() {
|
|
93
|
-
with open(main_jac, "w") as f {
|
|
94
|
-
f.write(
|
|
95
|
-
f'''"""Main entry point for {project_name}."""
|
|
96
|
-
|
|
97
|
-
with entry {{
|
|
98
|
-
print("Hello from {project_name}!");
|
|
99
|
-
}}
|
|
100
|
-
'''
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
print(f"Created {main_jac}");
|
|
104
|
-
}
|
|
68
|
+
# Handle client-side project creation
|
|
69
|
+
cwd = pathlib.Path(os.getcwd());
|
|
70
|
+
name = ctx.get_arg("name", "main");
|
|
71
|
+
force = ctx.get_arg("force", False);
|
|
72
|
+
skip_install = ctx.get_arg("skip", False);
|
|
73
|
+
verbose = ctx.get_arg("verbose", False);
|
|
105
74
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
75
|
+
try {
|
|
76
|
+
_create_client_project(cwd, name, force, skip_install, verbose);
|
|
77
|
+
# Cancel core handler with success code
|
|
78
|
+
ctx.set_data("cancel_execution", True);
|
|
79
|
+
ctx.set_data("cancel_return_code", 0);
|
|
80
|
+
} except SystemExit as e {
|
|
81
|
+
# Preserve exit code from sys.exit() calls
|
|
82
|
+
ctx.set_data("cancel_execution", True);
|
|
83
|
+
ctx.set_data("cancel_return_code", e.code if e.code is not None else 1);
|
|
84
|
+
} except Exception as e {
|
|
85
|
+
print(f"Error creating client project: {e}", file=sys.stderr);
|
|
86
|
+
ctx.set_data("cancel_execution", True);
|
|
87
|
+
ctx.set_data("cancel_return_code", 1);
|
|
110
88
|
}
|
|
111
|
-
|
|
112
|
-
_create_gitignore(cwd, client=False);
|
|
113
|
-
|
|
114
|
-
print(f"\nProject '{project_name}' initialized successfully!");
|
|
115
|
-
print("\nNext steps:");
|
|
116
|
-
print(" jac run main.jac # Run the main entry point");
|
|
117
|
-
print(" jac add <package> # Add dependencies");
|
|
118
|
-
print(" jac install # Install all dependencies");
|
|
119
89
|
}
|
|
120
90
|
|
|
121
91
|
"""Create a client-side Jac project with organized folder structure."""
|
|
@@ -166,23 +136,29 @@ def _create_client_project(
|
|
|
166
136
|
|
|
167
137
|
print(f"Creating Jac client application: {project_name}");
|
|
168
138
|
|
|
169
|
-
|
|
170
|
-
src_dir.mkdir(parents=True, exist_ok=True);
|
|
171
|
-
|
|
172
|
-
components_dir = src_dir / "components";
|
|
139
|
+
components_dir = project_path / "components";
|
|
173
140
|
components_dir.mkdir(parents=True, exist_ok=True);
|
|
174
141
|
|
|
175
142
|
assets_dir = project_path / "assets";
|
|
176
143
|
assets_dir.mkdir(parents=True, exist_ok=True);
|
|
177
144
|
|
|
178
|
-
(project_path / ".client
|
|
145
|
+
(project_path / ".jac" / "client").mkdir(parents=True, exist_ok=True);
|
|
179
146
|
|
|
180
147
|
toml_path = project_path / "jac.toml";
|
|
181
148
|
toml_content = f'''[project]
|
|
182
149
|
name = "{project_name}"
|
|
183
150
|
version = "1.0.0"
|
|
184
151
|
description = "Jac client application: {project_name}"
|
|
185
|
-
entry-point = "
|
|
152
|
+
entry-point = "main.jac"
|
|
153
|
+
|
|
154
|
+
[dependencies.npm]
|
|
155
|
+
"jac-client-node" = "1.0.3"
|
|
156
|
+
|
|
157
|
+
[dependencies.npm.dev]
|
|
158
|
+
"@jac-client/dev-deps" = "1.0.0"
|
|
159
|
+
|
|
160
|
+
[serve]
|
|
161
|
+
base_route_app = "app"
|
|
186
162
|
|
|
187
163
|
[plugins.client]
|
|
188
164
|
# Vite bundler configuration (optional overrides)
|
|
@@ -194,16 +170,16 @@ entry-point = "src/app.jac"
|
|
|
194
170
|
}
|
|
195
171
|
print(f"Created {toml_path}");
|
|
196
172
|
|
|
197
|
-
|
|
173
|
+
main_jac_content = '''"""Main entry point for the Jac client application."""
|
|
198
174
|
|
|
199
|
-
# Client-side imports
|
|
200
|
-
cl import from react {
|
|
201
|
-
cl import from
|
|
175
|
+
# Client-side imports (useState is auto-injected when using `has` variables)
|
|
176
|
+
cl import from react { useEffect }
|
|
177
|
+
cl import from .components.Button { Button }
|
|
202
178
|
|
|
203
179
|
# Client-side component
|
|
204
180
|
cl {
|
|
205
181
|
def:pub app() -> any {
|
|
206
|
-
|
|
182
|
+
has count: int = 0;
|
|
207
183
|
|
|
208
184
|
useEffect(lambda -> None {
|
|
209
185
|
console.log("Count updated:", count);
|
|
@@ -215,12 +191,12 @@ cl {
|
|
|
215
191
|
<div style={{display: "flex", gap: "1rem", marginTop: "1rem"}}>
|
|
216
192
|
<Button
|
|
217
193
|
label="Increment"
|
|
218
|
-
onClick={lambda -> None {
|
|
194
|
+
onClick={lambda -> None { count = count + 1; }}
|
|
219
195
|
variant="primary"
|
|
220
196
|
/>
|
|
221
197
|
<Button
|
|
222
198
|
label="Reset"
|
|
223
|
-
onClick={lambda -> None {
|
|
199
|
+
onClick={lambda -> None { count = 0; }}
|
|
224
200
|
variant="secondary"
|
|
225
201
|
/>
|
|
226
202
|
</div>
|
|
@@ -228,79 +204,62 @@ cl {
|
|
|
228
204
|
}
|
|
229
205
|
}
|
|
230
206
|
''';
|
|
231
|
-
with open(
|
|
232
|
-
f.write(
|
|
207
|
+
with open(project_path / "main.jac", 'w') as f {
|
|
208
|
+
f.write(main_jac_content);
|
|
233
209
|
}
|
|
234
|
-
print("Created
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
210
|
+
print("Created main.jac");
|
|
211
|
+
|
|
212
|
+
button_cl_jac_content = '''"""Button component for the Jac client application."""
|
|
213
|
+
|
|
214
|
+
def:pub Button(label: str, onClick: any, variant: str = "primary", disabled: bool = False) -> any {
|
|
215
|
+
base_styles = {
|
|
216
|
+
"padding": "0.75rem 1.5rem",
|
|
217
|
+
"fontSize": "1rem",
|
|
218
|
+
"fontWeight": "600",
|
|
219
|
+
"borderRadius": "0.5rem",
|
|
220
|
+
"border": "none",
|
|
221
|
+
"cursor": "not-allowed" if disabled else "pointer",
|
|
222
|
+
"transition": "all 0.2s ease"
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
variant_styles = {
|
|
226
|
+
"primary": {
|
|
227
|
+
"backgroundColor": "#9ca3af" if disabled else "#3b82f6",
|
|
228
|
+
"color": "#ffffff"
|
|
229
|
+
},
|
|
230
|
+
"secondary": {
|
|
231
|
+
"backgroundColor": "#e5e7eb" if disabled else "#6b7280",
|
|
232
|
+
"color": "#ffffff"
|
|
233
|
+
}
|
|
234
|
+
};
|
|
244
235
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
disabled = false
|
|
250
|
-
}) => {
|
|
251
|
-
const baseStyles: React.CSSProperties = {
|
|
252
|
-
padding: '0.75rem 1.5rem',
|
|
253
|
-
fontSize: '1rem',
|
|
254
|
-
fontWeight: '600',
|
|
255
|
-
borderRadius: '0.5rem',
|
|
256
|
-
border: 'none',
|
|
257
|
-
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
258
|
-
transition: 'all 0.2s ease',
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
const variantStyles: Record<string, React.CSSProperties> = {
|
|
262
|
-
primary: {
|
|
263
|
-
backgroundColor: disabled ? '#9ca3af' : '#3b82f6',
|
|
264
|
-
color: '#ffffff',
|
|
265
|
-
},
|
|
266
|
-
secondary: {
|
|
267
|
-
backgroundColor: disabled ? '#e5e7eb' : '#6b7280',
|
|
268
|
-
color: '#ffffff',
|
|
269
|
-
},
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
return (
|
|
273
|
-
<button
|
|
274
|
-
style={{ ...baseStyles, ...variantStyles[variant] }}
|
|
275
|
-
onClick={onClick}
|
|
276
|
-
disabled={disabled}
|
|
236
|
+
return <button
|
|
237
|
+
style={{**base_styles, **variant_styles[variant]}}
|
|
238
|
+
onClick={onClick}
|
|
239
|
+
disabled={disabled}
|
|
277
240
|
>
|
|
278
|
-
|
|
279
|
-
</button
|
|
280
|
-
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
export default Button;
|
|
241
|
+
{label}
|
|
242
|
+
</button>;
|
|
243
|
+
}
|
|
284
244
|
''';
|
|
285
|
-
with open(components_dir / "Button.
|
|
286
|
-
f.write(
|
|
245
|
+
with open(components_dir / "Button.cl.jac", 'w') as f {
|
|
246
|
+
f.write(button_cl_jac_content);
|
|
287
247
|
}
|
|
288
|
-
print("Created
|
|
248
|
+
print("Created components/Button.cl.jac");
|
|
289
249
|
|
|
290
250
|
readme_content = f''' # {project_name}
|
|
291
251
|
|
|
292
252
|
|
|
293
|
-
A Jac client-side application with React
|
|
253
|
+
A Jac client-side application with React support.
|
|
294
254
|
|
|
295
255
|
## Project Structure
|
|
296
256
|
|
|
297
257
|
```
|
|
298
258
|
{project_name}/
|
|
299
259
|
├── jac.toml # Project configuration
|
|
300
|
-
├──
|
|
301
|
-
|
|
302
|
-
│ └──
|
|
303
|
-
│ └── Button.tsx # Example TypeScript component
|
|
260
|
+
├── main.jac # Main application entry
|
|
261
|
+
├── components/ # Reusable components
|
|
262
|
+
│ └── Button.cl.jac # Example Jac component
|
|
304
263
|
├── assets/ # Static assets (images, fonts, etc.)
|
|
305
264
|
└── build/ # Build output (generated)
|
|
306
265
|
```
|
|
@@ -310,15 +269,15 @@ A Jac client-side application with React and TypeScript support.
|
|
|
310
269
|
Start the development server:
|
|
311
270
|
|
|
312
271
|
```bash
|
|
313
|
-
jac
|
|
272
|
+
jac start main.jac
|
|
314
273
|
```
|
|
315
274
|
|
|
316
|
-
##
|
|
275
|
+
## Components
|
|
317
276
|
|
|
318
|
-
Create
|
|
277
|
+
Create Jac components in `components/` as `.cl.jac` files and import them:
|
|
319
278
|
|
|
320
279
|
```jac
|
|
321
|
-
cl import from
|
|
280
|
+
cl import from .components.Button {{ Button }}
|
|
322
281
|
```
|
|
323
282
|
|
|
324
283
|
## Adding Dependencies
|
|
@@ -334,7 +293,7 @@ jac add --cl react-router-dom
|
|
|
334
293
|
}
|
|
335
294
|
print("Created README.md");
|
|
336
295
|
|
|
337
|
-
_create_gitignore(project_path
|
|
296
|
+
_create_gitignore(project_path);
|
|
338
297
|
|
|
339
298
|
# Install default packages unless --skip is specified
|
|
340
299
|
if not skip {
|
|
@@ -346,15 +305,15 @@ jac add --cl react-router-dom
|
|
|
346
305
|
if name and name != cwd.name {
|
|
347
306
|
print("\nNext steps:");
|
|
348
307
|
print(f" cd {name}");
|
|
349
|
-
print(" jac
|
|
308
|
+
print(" jac start main.jac");
|
|
350
309
|
} else {
|
|
351
310
|
print("\nNext steps:");
|
|
352
|
-
print(" jac
|
|
311
|
+
print(" jac start main.jac");
|
|
353
312
|
}
|
|
354
313
|
}
|
|
355
314
|
|
|
356
|
-
"""Create .gitignore file with
|
|
357
|
-
def _create_gitignore(project_path: pathlib.Path
|
|
315
|
+
"""Create .gitignore file with client-specific entries."""
|
|
316
|
+
def _create_gitignore(project_path: pathlib.Path) -> None {
|
|
358
317
|
gitignore_entries = [
|
|
359
318
|
"# Jac project",
|
|
360
319
|
"packages/",
|
|
@@ -372,24 +331,17 @@ def _create_gitignore(project_path: pathlib.Path, client: bool = False) -> None
|
|
|
372
331
|
"# IDE",
|
|
373
332
|
".idea/",
|
|
374
333
|
".vscode/",
|
|
375
|
-
"*.swp"
|
|
334
|
+
"*.swp",
|
|
335
|
+
"",
|
|
336
|
+
"# Node.js",
|
|
337
|
+
"node_modules/",
|
|
338
|
+
"",
|
|
339
|
+
"# Jac build artifacts",
|
|
340
|
+
".jac/",
|
|
341
|
+
"*.session",
|
|
342
|
+
"*.session.*"
|
|
376
343
|
];
|
|
377
344
|
|
|
378
|
-
if client {
|
|
379
|
-
gitignore_entries.extend(
|
|
380
|
-
[
|
|
381
|
-
"",
|
|
382
|
-
"# Node.js",
|
|
383
|
-
"node_modules/",
|
|
384
|
-
"",
|
|
385
|
-
"# Jac Client",
|
|
386
|
-
".client-build/",
|
|
387
|
-
"*.session",
|
|
388
|
-
"*.session.*"
|
|
389
|
-
]
|
|
390
|
-
);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
345
|
gitignore_path = project_path / ".gitignore";
|
|
394
346
|
if gitignore_path.exists() {
|
|
395
347
|
with open(gitignore_path, "r") as f {
|
|
@@ -415,7 +367,7 @@ def _create_gitignore(project_path: pathlib.Path, client: bool = False) -> None
|
|
|
415
367
|
}
|
|
416
368
|
}
|
|
417
369
|
|
|
418
|
-
"""Install default npm packages in .client
|
|
370
|
+
"""Install default npm packages in .jac/client directory."""
|
|
419
371
|
def _install_default_packages(
|
|
420
372
|
project_path: pathlib.Path, verbose: bool = False
|
|
421
373
|
) -> None {
|
|
@@ -441,13 +393,13 @@ def _install_default_packages(
|
|
|
441
393
|
# Generate package.json with default packages (defaults are added automatically)
|
|
442
394
|
bundler.create_package_json(project_name=project_name);
|
|
443
395
|
|
|
444
|
-
# Ensure .client
|
|
445
|
-
|
|
446
|
-
|
|
396
|
+
# Ensure .jac/client directory exists
|
|
397
|
+
client_dir = bundler._get_client_dir();
|
|
398
|
+
client_dir.mkdir(parents=True, exist_ok=True);
|
|
447
399
|
|
|
448
|
-
# Copy package.json to .client
|
|
449
|
-
configs_package_json =
|
|
450
|
-
build_package_json =
|
|
400
|
+
# Copy package.json to .jac/client/ for npm install
|
|
401
|
+
configs_package_json = client_dir / 'configs' / 'package.json';
|
|
402
|
+
build_package_json = client_dir / 'package.json';
|
|
451
403
|
|
|
452
404
|
if not configs_package_json.exists() {
|
|
453
405
|
print(
|
|
@@ -457,7 +409,7 @@ def _install_default_packages(
|
|
|
457
409
|
return;
|
|
458
410
|
}
|
|
459
411
|
|
|
460
|
-
# Always copy the generated package.json to .client
|
|
412
|
+
# Always copy the generated package.json to .jac/client/ for npm install
|
|
461
413
|
shutil.copy2(configs_package_json, build_package_json);
|
|
462
414
|
|
|
463
415
|
# Read package data for verbose output
|
|
@@ -485,27 +437,27 @@ def _install_default_packages(
|
|
|
485
437
|
print("\nRunning npm install...");
|
|
486
438
|
}
|
|
487
439
|
|
|
488
|
-
# Run npm install in .client
|
|
440
|
+
# Run npm install in .jac/client/ directory
|
|
489
441
|
try {
|
|
490
442
|
if verbose {
|
|
491
443
|
# Stream output for visibility in verbose mode
|
|
492
444
|
subprocess.run(
|
|
493
|
-
['npm', 'install', '--progress'], cwd=
|
|
445
|
+
['npm', 'install', '--progress'], cwd=client_dir, check=True
|
|
494
446
|
);
|
|
495
447
|
} else {
|
|
496
448
|
# Quiet mode: capture output
|
|
497
449
|
subprocess.run(
|
|
498
450
|
['npm', 'install'],
|
|
499
|
-
cwd=
|
|
451
|
+
cwd=client_dir,
|
|
500
452
|
check=True,
|
|
501
453
|
capture_output=True,
|
|
502
454
|
text=True
|
|
503
455
|
);
|
|
504
456
|
}
|
|
505
457
|
|
|
506
|
-
# Move package-lock.json to
|
|
507
|
-
build_package_lock =
|
|
508
|
-
configs_dir =
|
|
458
|
+
# Move package-lock.json to configs/ if it was created
|
|
459
|
+
build_package_lock = client_dir / 'package-lock.json';
|
|
460
|
+
configs_dir = client_dir / 'configs';
|
|
509
461
|
configs_package_lock = configs_dir / 'package-lock.json';
|
|
510
462
|
if build_package_lock.exists() {
|
|
511
463
|
configs_dir.mkdir(parents=True, exist_ok=True);
|
|
@@ -535,7 +487,7 @@ def _install_default_packages(
|
|
|
535
487
|
);
|
|
536
488
|
print("You can install packages later with: jac add --cl", file=sys.stderr);
|
|
537
489
|
} finally {
|
|
538
|
-
# Clean up temporary package.json in .client
|
|
490
|
+
# Clean up temporary package.json in .jac/client/
|
|
539
491
|
if build_package_json.exists() {
|
|
540
492
|
build_package_json.unlink();
|
|
541
493
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Client-side runtime for Jac JSX and walker interactions."""
|
|
2
2
|
|
|
3
3
|
import from 'react' { * as React }
|
|
4
|
+
import from 'react' { useState as reactUseState }
|
|
4
5
|
import from 'react-dom/client' { * as ReactDOM }
|
|
5
6
|
import from 'react-router-dom' {
|
|
6
7
|
HashRouter as ReactRouterHashRouter,
|
|
@@ -15,7 +16,9 @@ import from 'react-router-dom' {
|
|
|
15
16
|
|
|
16
17
|
def : pub __jacJsx(tag: any, props: dict = {}, children: any = []) -> any;
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
# React hooks re-exported for auto-injection by `has` variables
|
|
20
|
+
glob : pub useState = reactUseState,
|
|
21
|
+
Router = ReactRouterHashRouter,
|
|
19
22
|
Routes = ReactRouterRoutes,
|
|
20
23
|
Route = ReactRouterRoute,
|
|
21
24
|
Link = ReactRouterLink,
|
|
@@ -36,3 +39,4 @@ def : pub jacIsLoggedIn -> bool;
|
|
|
36
39
|
def : pub __getLocalStorage(key: str) -> str;
|
|
37
40
|
def : pub __setLocalStorage(key: str, value: str) -> None;
|
|
38
41
|
def : pub __removeLocalStorage(key: str) -> None;
|
|
42
|
+
# React Router components
|