jac-client 0.2.2__py3-none-any.whl → 0.2.6__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/assets/workers/worker.py +5 -0
- jac_client/examples/all-in-one/src/app.jac +841 -0
- jac_client/examples/all-in-one/{button.jac → src/button.jac} +1 -1
- jac_client/examples/all-in-one/{components → src/components}/button.jac +1 -1
- jac_client/examples/asset-serving/css-with-image/{app.jac → src/app.jac} +2 -2
- jac_client/examples/asset-serving/image-asset/{app.jac → src/app.jac} +2 -2
- jac_client/examples/asset-serving/import-alias/{app.jac → src/app.jac} +7 -7
- jac_client/examples/basic/{app.jac → src/app.jac} +2 -2
- jac_client/examples/basic-auth/src/app.jac +377 -0
- jac_client/examples/basic-auth-with-router/{app.jac → src/app.jac} +18 -18
- jac_client/examples/basic-full-stack/{app.jac → src/app.jac} +175 -130
- jac_client/examples/css-styling/js-styling/{app.jac → src/app.jac} +6 -6
- jac_client/examples/css-styling/material-ui/{app.jac → src/app.jac} +5 -5
- jac_client/examples/css-styling/pure-css/{app.jac → src/app.jac} +6 -6
- jac_client/examples/css-styling/sass-example/{app.jac → src/app.jac} +6 -6
- jac_client/examples/css-styling/styled-components/{app.jac → src/app.jac} +5 -5
- jac_client/examples/css-styling/tailwind-example/{app.jac → src/app.jac} +6 -6
- jac_client/examples/full-stack-with-auth/{app.jac → src/app.jac} +37 -37
- jac_client/examples/little-x/{app.jac → src/app.jac} +27 -32
- jac_client/examples/little-x/src/submit-button.jac +16 -0
- jac_client/examples/nested-folders/nested-advance/{ButtonRoot.jac → src/ButtonRoot.jac} +1 -1
- jac_client/examples/nested-folders/nested-advance/{app.jac → src/app.jac} +1 -1
- jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/ButtonSecondL.jac +1 -1
- jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/Card.jac +1 -1
- jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/level2/ButtonThirdL.jac +1 -1
- jac_client/examples/nested-folders/nested-basic/{app.jac → src/app.jac} +2 -2
- jac_client/examples/nested-folders/nested-basic/{button.jac → src/button.jac} +1 -1
- jac_client/examples/nested-folders/nested-basic/{components → src/components}/button.jac +1 -1
- jac_client/examples/ts-support/src/app.jac +35 -0
- jac_client/examples/with-router/{app.jac → src/app.jac} +11 -11
- jac_client/plugin/cli.jac +547 -0
- jac_client/plugin/client.jac +52 -0
- jac_client/plugin/client_runtime.cl.jac +38 -0
- jac_client/plugin/impl/client.impl.jac +134 -0
- jac_client/plugin/impl/client_runtime.impl.jac +177 -0
- jac_client/plugin/impl/vite_client_bundle.impl.jac +72 -0
- jac_client/plugin/plugin_config.jac +195 -0
- jac_client/plugin/src/__init__.jac +20 -0
- jac_client/plugin/src/asset_processor.jac +33 -0
- jac_client/plugin/src/babel_processor.jac +18 -0
- jac_client/plugin/src/compiler.jac +66 -0
- jac_client/plugin/src/config_loader.jac +32 -0
- jac_client/plugin/src/impl/asset_processor.impl.jac +127 -0
- jac_client/plugin/src/impl/babel_processor.impl.jac +84 -0
- jac_client/plugin/src/impl/compiler.impl.jac +251 -0
- jac_client/plugin/src/impl/config_loader.impl.jac +119 -0
- jac_client/plugin/src/impl/import_processor.impl.jac +33 -0
- jac_client/plugin/src/impl/jac_to_js.impl.jac +41 -0
- jac_client/plugin/src/impl/package_installer.impl.jac +105 -0
- jac_client/plugin/src/impl/vite_bundler.impl.jac +513 -0
- jac_client/plugin/src/import_processor.jac +19 -0
- jac_client/plugin/src/jac_to_js.jac +35 -0
- jac_client/plugin/src/package_installer.jac +26 -0
- jac_client/plugin/src/vite_bundler.jac +36 -0
- jac_client/plugin/vite_client_bundle.jac +31 -0
- jac_client/tests/conftest.py +281 -0
- jac_client/tests/fixtures/basic-app/app.jac +2 -2
- jac_client/tests/fixtures/cl_file/app.cl.jac +2 -2
- jac_client/tests/fixtures/client_app_with_antd/app.jac +1 -1
- jac_client/tests/fixtures/js_import/app.jac +5 -5
- jac_client/tests/fixtures/spawn_test/app.jac +7 -7
- jac_client/tests/fixtures/with-ts/app.jac +35 -0
- jac_client/tests/test_cli.py +755 -0
- jac_client/tests/test_it.py +347 -67
- {jac_client-0.2.2.dist-info → jac_client-0.2.6.dist-info}/METADATA +30 -24
- jac_client-0.2.6.dist-info/RECORD +74 -0
- {jac_client-0.2.2.dist-info → jac_client-0.2.6.dist-info}/WHEEL +2 -1
- jac_client-0.2.6.dist-info/entry_points.txt +4 -0
- jac_client-0.2.6.dist-info/top_level.txt +1 -0
- jac_client/docs/README.md +0 -689
- jac_client/docs/advanced-state.md +0 -1265
- jac_client/docs/asset-serving/intro.md +0 -209
- jac_client/docs/assets/pipe_line-v2.svg +0 -32
- jac_client/docs/assets/pipe_line.png +0 -0
- jac_client/docs/file-system/app.jac.md +0 -121
- jac_client/docs/file-system/backend-frontend.md +0 -217
- jac_client/docs/file-system/intro.md +0 -72
- jac_client/docs/file-system/nested-imports.md +0 -348
- jac_client/docs/guide-example/intro.md +0 -115
- jac_client/docs/guide-example/step-01-setup.md +0 -270
- jac_client/docs/guide-example/step-02-components.md +0 -416
- jac_client/docs/guide-example/step-03-styling.md +0 -478
- jac_client/docs/guide-example/step-04-todo-ui.md +0 -477
- jac_client/docs/guide-example/step-05-local-state.md +0 -530
- jac_client/docs/guide-example/step-06-events.md +0 -749
- jac_client/docs/guide-example/step-07-effects.md +0 -468
- jac_client/docs/guide-example/step-08-walkers.md +0 -534
- jac_client/docs/guide-example/step-09-authentication.md +0 -586
- jac_client/docs/guide-example/step-10-routing.md +0 -539
- jac_client/docs/guide-example/step-11-final.md +0 -963
- jac_client/docs/imports.md +0 -1141
- jac_client/docs/lifecycle-hooks.md +0 -773
- jac_client/docs/routing.md +0 -659
- jac_client/docs/styling/intro.md +0 -249
- jac_client/docs/styling/js-styling.md +0 -367
- jac_client/docs/styling/material-ui.md +0 -341
- jac_client/docs/styling/pure-css.md +0 -299
- jac_client/docs/styling/sass.md +0 -403
- jac_client/docs/styling/styled-components.md +0 -395
- jac_client/docs/styling/tailwind.md +0 -298
- jac_client/examples/all-in-one/.babelrc +0 -9
- jac_client/examples/all-in-one/README.md +0 -16
- jac_client/examples/all-in-one/app.jac +0 -426
- jac_client/examples/all-in-one/assets/burger.png +0 -0
- jac_client/examples/all-in-one/package.json +0 -29
- jac_client/examples/all-in-one/styles.css +0 -26
- jac_client/examples/all-in-one/vite.config.js +0 -28
- jac_client/examples/asset-serving/css-with-image/.babelrc +0 -9
- jac_client/examples/asset-serving/css-with-image/README.md +0 -91
- jac_client/examples/asset-serving/css-with-image/assets/burger.png +0 -0
- jac_client/examples/asset-serving/css-with-image/package.json +0 -28
- jac_client/examples/asset-serving/css-with-image/styles.css +0 -26
- jac_client/examples/asset-serving/css-with-image/vite.config.js +0 -28
- jac_client/examples/asset-serving/image-asset/.babelrc +0 -9
- jac_client/examples/asset-serving/image-asset/README.md +0 -119
- jac_client/examples/asset-serving/image-asset/assets/burger.png +0 -0
- jac_client/examples/asset-serving/image-asset/package.json +0 -28
- jac_client/examples/asset-serving/image-asset/styles.css +0 -26
- jac_client/examples/asset-serving/image-asset/vite.config.js +0 -28
- jac_client/examples/asset-serving/import-alias/.babelrc +0 -9
- jac_client/examples/asset-serving/import-alias/README.md +0 -83
- jac_client/examples/asset-serving/import-alias/assets/burger.png +0 -0
- jac_client/examples/asset-serving/import-alias/package.json +0 -28
- jac_client/examples/asset-serving/import-alias/vite.config.js +0 -28
- jac_client/examples/basic/.babelrc +0 -9
- jac_client/examples/basic/README.md +0 -16
- jac_client/examples/basic/package.json +0 -27
- jac_client/examples/basic/vite.config.js +0 -27
- jac_client/examples/basic-auth/.babelrc +0 -9
- jac_client/examples/basic-auth/README.md +0 -16
- jac_client/examples/basic-auth/app.jac +0 -308
- jac_client/examples/basic-auth/package.json +0 -27
- jac_client/examples/basic-auth/vite.config.js +0 -27
- jac_client/examples/basic-auth-with-router/.babelrc +0 -9
- jac_client/examples/basic-auth-with-router/README.md +0 -60
- jac_client/examples/basic-auth-with-router/package.json +0 -28
- jac_client/examples/basic-auth-with-router/vite.config.js +0 -27
- jac_client/examples/basic-full-stack/.babelrc +0 -9
- jac_client/examples/basic-full-stack/README.md +0 -18
- jac_client/examples/basic-full-stack/package.json +0 -28
- jac_client/examples/basic-full-stack/vite.config.js +0 -27
- jac_client/examples/css-styling/js-styling/.babelrc +0 -9
- jac_client/examples/css-styling/js-styling/README.md +0 -183
- jac_client/examples/css-styling/js-styling/package.json +0 -28
- jac_client/examples/css-styling/js-styling/styles.js +0 -100
- jac_client/examples/css-styling/js-styling/vite.config.js +0 -27
- jac_client/examples/css-styling/material-ui/.babelrc +0 -9
- jac_client/examples/css-styling/material-ui/README.md +0 -16
- jac_client/examples/css-styling/material-ui/package.json +0 -32
- jac_client/examples/css-styling/material-ui/vite.config.js +0 -27
- jac_client/examples/css-styling/pure-css/.babelrc +0 -9
- jac_client/examples/css-styling/pure-css/README.md +0 -16
- jac_client/examples/css-styling/pure-css/package.json +0 -28
- jac_client/examples/css-styling/pure-css/styles.css +0 -111
- jac_client/examples/css-styling/pure-css/vite.config.js +0 -27
- jac_client/examples/css-styling/sass-example/.babelrc +0 -9
- jac_client/examples/css-styling/sass-example/README.md +0 -16
- jac_client/examples/css-styling/sass-example/package.json +0 -29
- jac_client/examples/css-styling/sass-example/styles.scss +0 -153
- jac_client/examples/css-styling/sass-example/vite.config.js +0 -27
- jac_client/examples/css-styling/styled-components/.babelrc +0 -9
- jac_client/examples/css-styling/styled-components/README.md +0 -16
- jac_client/examples/css-styling/styled-components/package.json +0 -29
- jac_client/examples/css-styling/styled-components/styled.js +0 -90
- jac_client/examples/css-styling/styled-components/vite.config.js +0 -27
- jac_client/examples/css-styling/tailwind-example/.babelrc +0 -9
- jac_client/examples/css-styling/tailwind-example/README.md +0 -16
- jac_client/examples/css-styling/tailwind-example/global.css +0 -1
- jac_client/examples/css-styling/tailwind-example/package.json +0 -30
- jac_client/examples/css-styling/tailwind-example/vite.config.js +0 -29
- jac_client/examples/full-stack-with-auth/.babelrc +0 -9
- jac_client/examples/full-stack-with-auth/README.md +0 -16
- jac_client/examples/full-stack-with-auth/package.json +0 -28
- jac_client/examples/full-stack-with-auth/vite.config.js +0 -29
- jac_client/examples/little-x/package.json +0 -23
- jac_client/examples/little-x/submit-button.jac +0 -8
- jac_client/examples/nested-folders/nested-advance/.babelrc +0 -9
- jac_client/examples/nested-folders/nested-advance/README.md +0 -77
- jac_client/examples/nested-folders/nested-advance/package.json +0 -29
- jac_client/examples/nested-folders/nested-advance/vite.config.js +0 -28
- jac_client/examples/nested-folders/nested-basic/.babelrc +0 -9
- jac_client/examples/nested-folders/nested-basic/README.md +0 -183
- jac_client/examples/nested-folders/nested-basic/app.js +0 -7
- jac_client/examples/nested-folders/nested-basic/package.json +0 -28
- jac_client/examples/nested-folders/nested-basic/vite.config.js +0 -27
- jac_client/examples/with-router/.babelrc +0 -9
- jac_client/examples/with-router/README.md +0 -17
- jac_client/examples/with-router/package.json +0 -28
- jac_client/examples/with-router/vite.config.js +0 -27
- jac_client/plugin/cli.py +0 -244
- jac_client/plugin/client.py +0 -152
- jac_client/plugin/client_runtime.jac +0 -234
- jac_client/plugin/vite_client_bundle.py +0 -503
- jac_client/tests/fixtures/js_import/utils.js +0 -21
- jac_client/tests/fixtures/package-lock.json +0 -329
- jac_client/tests/fixtures/package.json +0 -11
- jac_client/tests/test_asset_examples.py +0 -322
- jac_client/tests/test_cl.py +0 -530
- jac_client/tests/test_create_jac_app.py +0 -131
- jac_client/tests/test_nested_file.py +0 -374
- jac_client-0.2.2.dist-info/RECORD +0 -171
- jac_client-0.2.2.dist-info/entry_points.txt +0 -4
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import from jaclang.project.config { get_config }
|
|
2
|
+
|
|
3
|
+
"""Send static file response (images, fonts, etc.)."""
|
|
4
|
+
impl JacClient.send_static_file(
|
|
5
|
+
handler: BaseHTTPRequestHandler, file_path: Path, content_type: (str | None) = None
|
|
6
|
+
) -> None {
|
|
7
|
+
import from jaclang.runtimelib.server { ResponseBuilder }
|
|
8
|
+
if (not file_path.exists() or not file_path.is_file()) {
|
|
9
|
+
ResponseBuilder.send_json(handler, 404, {'error': 'File not found'});
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
file_content = file_path.read_bytes();
|
|
14
|
+
if (content_type is None) {
|
|
15
|
+
(content_type, _) = mimetypes.guess_type(str(file_path));
|
|
16
|
+
if (content_type is None) {
|
|
17
|
+
content_type = 'application/octet-stream';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
handler.send_response(200);
|
|
21
|
+
handler.send_header('Content-Type', content_type);
|
|
22
|
+
handler.send_header('Content-Length', str(len(file_content)));
|
|
23
|
+
handler.send_header('Cache-Control', 'public, max-age=3600');
|
|
24
|
+
ResponseBuilder._add_cors_headers(handler);
|
|
25
|
+
ResponseBuilder._add_custom_headers(handler);
|
|
26
|
+
handler.end_headers();
|
|
27
|
+
handler.wfile.write(file_content);
|
|
28
|
+
} except Exception as exc {
|
|
29
|
+
ResponseBuilder.send_json(handler, 500, {'error': str(exc)});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
"""Get a module introspector for the supplied module."""
|
|
34
|
+
impl JacClient.get_module_introspector(
|
|
35
|
+
module_name: str, base_path: (str | None)
|
|
36
|
+
) -> ModuleIntrospector {
|
|
37
|
+
return JacClientModuleIntrospector(module_name, base_path);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
"""Build a client bundle for the supplied module."""
|
|
41
|
+
impl JacClient.build_client_bundle(
|
|
42
|
+
module: types.ModuleType, force: bool = False
|
|
43
|
+
) -> ClientBundle {
|
|
44
|
+
builder = JacClient.get_client_bundle_builder();
|
|
45
|
+
return builder.build(module, force=force);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
"""Get the client bundle builder instance."""
|
|
49
|
+
impl JacClient.get_client_bundle_builder -> ViteClientBundleBuilder {
|
|
50
|
+
import from jaclang.project.config { find_project_root }
|
|
51
|
+
# Find project root by looking for jac.toml (base_path_dir might be src/ for entry files)
|
|
52
|
+
base_path_dir = Path(Jac.base_path_dir);
|
|
53
|
+
project_root_result = find_project_root(base_path_dir);
|
|
54
|
+
if project_root_result {
|
|
55
|
+
(base_path, _) = project_root_result;
|
|
56
|
+
} else {
|
|
57
|
+
# Fallback to base_path_dir if no project root found
|
|
58
|
+
base_path = base_path_dir;
|
|
59
|
+
}
|
|
60
|
+
# package.json should only exist in .client-build/.jac-client.configs/
|
|
61
|
+
generated_package_json = base_path / '.client-build' / '.jac-client.configs' / 'package.json';
|
|
62
|
+
# Generate package.json if it doesn't exist
|
|
63
|
+
if not generated_package_json.exists() {
|
|
64
|
+
# Use ViteBundler to generate package.json from config.json
|
|
65
|
+
bundler = ViteBundler(base_path);
|
|
66
|
+
generated_path = bundler.create_package_json();
|
|
67
|
+
# Verify the file was created and resolve to absolute path
|
|
68
|
+
if not generated_path.exists() {
|
|
69
|
+
raise ClientBundleError(
|
|
70
|
+
f'Failed to generate package.json at {generated_path}'
|
|
71
|
+
) ;
|
|
72
|
+
}
|
|
73
|
+
package_json_path = generated_path.resolve();
|
|
74
|
+
} else {
|
|
75
|
+
package_json_path = generated_package_json.resolve();
|
|
76
|
+
}
|
|
77
|
+
# Final verification that package.json exists before creating builder
|
|
78
|
+
if not package_json_path.exists() {
|
|
79
|
+
raise ClientBundleError(
|
|
80
|
+
f'package.json not found at {package_json_path}. Expected at {generated_package_json}'
|
|
81
|
+
) ;
|
|
82
|
+
}
|
|
83
|
+
output_dir = base_path / '.client-build' / 'dist';
|
|
84
|
+
runtime_path = Path(__file__).with_name('client_runtime.cl.jac');
|
|
85
|
+
return ViteClientBundleBuilder(
|
|
86
|
+
runtime_path=runtime_path,
|
|
87
|
+
vite_package_json=package_json_path,
|
|
88
|
+
vite_output_dir=output_dir,
|
|
89
|
+
vite_minify=False
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
"""Render HTML page for client function using the Vite bundle."""
|
|
94
|
+
impl JacClientModuleIntrospector.render_page(
|
|
95
|
+
self: JacClientModuleIntrospector,
|
|
96
|
+
function_name: str,
|
|
97
|
+
args: dict[(str, Any)],
|
|
98
|
+
username: str
|
|
99
|
+
) -> dict[str, Any] {
|
|
100
|
+
self.load();
|
|
101
|
+
available_exports = (
|
|
102
|
+
set(self._client_manifest.get('exports', []))
|
|
103
|
+
or set(self.get_client_functions().keys())
|
|
104
|
+
);
|
|
105
|
+
if (function_name not in available_exports) {
|
|
106
|
+
raise ValueError(f"Client function '{function_name}' not found") ;
|
|
107
|
+
}
|
|
108
|
+
bundle_hash = self.ensure_bundle();
|
|
109
|
+
import from jaclang.project.config { find_project_root }
|
|
110
|
+
# Find project root by looking for jac.toml (base_path_dir might be src/ for entry files)
|
|
111
|
+
base_path_dir = Path(Jac.base_path_dir);
|
|
112
|
+
project_root_result = find_project_root(base_path_dir);
|
|
113
|
+
if project_root_result {
|
|
114
|
+
(base_path, _) = project_root_result;
|
|
115
|
+
} else {
|
|
116
|
+
# Fallback to base_path_dir if no project root found
|
|
117
|
+
base_path = base_path_dir;
|
|
118
|
+
}
|
|
119
|
+
dist_dir = base_path / '.client-build' / 'dist';
|
|
120
|
+
css_link = '';
|
|
121
|
+
css_file = dist_dir / 'main.css';
|
|
122
|
+
if css_file.exists() {
|
|
123
|
+
css_hash = hashlib.sha256(css_file.read_bytes()).hexdigest()[:8];
|
|
124
|
+
css_link = f'<link rel="stylesheet" href="/static/main.css?hash={css_hash}"/>';
|
|
125
|
+
}
|
|
126
|
+
head_content = f'<meta charset="utf-8"/>\n <title>{html.escape(
|
|
127
|
+
function_name
|
|
128
|
+
)}</title>';
|
|
129
|
+
if css_link {
|
|
130
|
+
head_content += f"\n {css_link}";
|
|
131
|
+
}
|
|
132
|
+
page = f'<!DOCTYPE html><html lang="en"><head>{head_content}</head><body><div id="root"></div><script src="/static/client.js?hash={bundle_hash}" defer></script></body></html>';
|
|
133
|
+
return {'html': page, 'bundle_hash': bundle_hash, 'bundle_code': self._bundle.code};
|
|
134
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
impl __jacJsx(tag: any, props: dict = {}, children: any = []) -> any {
|
|
2
|
+
if tag == None {
|
|
3
|
+
tag = React.Fragment;
|
|
4
|
+
}
|
|
5
|
+
childrenArray = [];
|
|
6
|
+
if children != None {
|
|
7
|
+
if Array.isArray(children) {
|
|
8
|
+
childrenArray = children;
|
|
9
|
+
} else {
|
|
10
|
+
childrenArray = [children];
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
reactChildren = [];
|
|
14
|
+
for child in childrenArray {
|
|
15
|
+
if child != None {
|
|
16
|
+
reactChildren.push(child);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if reactChildren.length > 0 {
|
|
20
|
+
args = [tag, props];
|
|
21
|
+
for child in reactChildren {
|
|
22
|
+
args.push(child);
|
|
23
|
+
}
|
|
24
|
+
return React.createElement.apply(React, args);
|
|
25
|
+
} else {
|
|
26
|
+
return React.createElement(tag, props);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
impl useRouter -> dict {
|
|
31
|
+
navigate = reactRouterUseNavigate();
|
|
32
|
+
location = reactRouterUseLocation();
|
|
33
|
+
params = reactRouterUseParams();
|
|
34
|
+
return {
|
|
35
|
+
"navigate": navigate,
|
|
36
|
+
"location": location,
|
|
37
|
+
"params": params,
|
|
38
|
+
"pathname": location.pathname,
|
|
39
|
+
"search": location.search,
|
|
40
|
+
"hash": location.hash
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
impl navigate(path: str) -> None {
|
|
45
|
+
window.location.hash = "#" + path;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
impl __jacSpawn(left: str, right: str = "", fields: dict = {}) -> any {
|
|
49
|
+
token = __getLocalStorage("jac_token");
|
|
50
|
+
url = f"/walker/{left}";
|
|
51
|
+
if right != "" {
|
|
52
|
+
url = f"/walker/{left}/{right}";
|
|
53
|
+
}
|
|
54
|
+
response = await fetch(
|
|
55
|
+
url,
|
|
56
|
+
{
|
|
57
|
+
"method": "POST",
|
|
58
|
+
"accept": "application/json",
|
|
59
|
+
"headers": {
|
|
60
|
+
"Content-Type": "application/json",
|
|
61
|
+
"Authorization": f"Bearer {token}" if token else ""
|
|
62
|
+
},
|
|
63
|
+
"body": JSON.stringify(fields)
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
if not response.ok {
|
|
67
|
+
error_text = await response.json();
|
|
68
|
+
raise Exception(f"Walker {walker} failed: {error_text}") ;
|
|
69
|
+
}
|
|
70
|
+
return await response.json();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
impl jacSpawn(left: str, right: str = "", fields: dict = {}) -> any {
|
|
74
|
+
return __jacSpawn(left, right, fields);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
impl __jacCallFunction(function_name: str, args: dict = {}) -> any {
|
|
78
|
+
token = __getLocalStorage("jac_token");
|
|
79
|
+
response = await fetch(
|
|
80
|
+
f"/function/{function_name}",
|
|
81
|
+
{
|
|
82
|
+
"method": "POST",
|
|
83
|
+
"headers": {
|
|
84
|
+
"Content-Type": "application/json",
|
|
85
|
+
"Authorization": f"Bearer {token}" if token else ""
|
|
86
|
+
},
|
|
87
|
+
"body": JSON.stringify({"args": args})
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
if not response.ok {
|
|
91
|
+
error_text = await response.text();
|
|
92
|
+
raise Exception(f"Function {function_name} failed: {error_text}") ;
|
|
93
|
+
}
|
|
94
|
+
data = JSON.parse(await response.text());
|
|
95
|
+
return data["result"];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
impl jacSignup(username: str, password: str) -> dict {
|
|
99
|
+
response = await fetch(
|
|
100
|
+
"/user/register",
|
|
101
|
+
{
|
|
102
|
+
"method": "POST",
|
|
103
|
+
"headers": {"Content-Type": "application/json"},
|
|
104
|
+
"body": JSON.stringify({"username": username, "password": password})
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
if response.ok {
|
|
108
|
+
data = JSON.parse(await response.text());
|
|
109
|
+
token = data["token"];
|
|
110
|
+
if token {
|
|
111
|
+
__setLocalStorage("jac_token", token);
|
|
112
|
+
return {"success": True, "token": token, "username": username};
|
|
113
|
+
}
|
|
114
|
+
return {"success": False, "error": "No token received"};
|
|
115
|
+
} else {
|
|
116
|
+
error_text = await response.text();
|
|
117
|
+
try {
|
|
118
|
+
error_data = JSON.parse(error_text);
|
|
119
|
+
return {
|
|
120
|
+
"success": False,
|
|
121
|
+
"error": error_data["error"]
|
|
122
|
+
if error_data["error"] != None
|
|
123
|
+
else "Signup failed"
|
|
124
|
+
};
|
|
125
|
+
} except Exception {
|
|
126
|
+
return {"success": False, "error": error_text};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
impl jacLogin(username: str, password: str) -> bool {
|
|
132
|
+
response = await fetch(
|
|
133
|
+
"/user/login",
|
|
134
|
+
{
|
|
135
|
+
"method": "POST",
|
|
136
|
+
"headers": {"Content-Type": "application/json"},
|
|
137
|
+
"body": JSON.stringify({"username": username, "password": password})
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
if response.ok {
|
|
141
|
+
data = JSON.parse(await response.text());
|
|
142
|
+
token = data["token"];
|
|
143
|
+
if token {
|
|
144
|
+
__setLocalStorage("jac_token", token);
|
|
145
|
+
return True;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return False;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
impl jacLogout -> None {
|
|
152
|
+
__removeLocalStorage("jac_token");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
impl jacIsLoggedIn -> bool {
|
|
156
|
+
token = __getLocalStorage("jac_token");
|
|
157
|
+
return token != None and token != "";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
impl __getLocalStorage(key: str) -> str {
|
|
161
|
+
storage = globalThis.localStorage;
|
|
162
|
+
return storage.getItem(key) if storage else "";
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
impl __setLocalStorage(key: str, value: str) -> None {
|
|
166
|
+
storage = globalThis.localStorage;
|
|
167
|
+
if storage {
|
|
168
|
+
storage.setItem(key, value);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
impl __removeLocalStorage(key: str) -> None {
|
|
173
|
+
storage = globalThis.localStorage;
|
|
174
|
+
if storage {
|
|
175
|
+
storage.removeItem(key);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Clean up the compiled directory and its contents."""
|
|
2
|
+
|
|
3
|
+
impl ViteClientBundleBuilder.cleanup_temp_dir(self: ViteClientBundleBuilder) -> None {
|
|
4
|
+
if (not self.vite_package_json or not self.vite_package_json.exists()) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
project_dir = self.vite_package_json.parent;
|
|
8
|
+
temp_dir = project_dir / 'compiled';
|
|
9
|
+
if temp_dir.exists() {
|
|
10
|
+
with contextlib.suppress(OSError, shutil.Error) {
|
|
11
|
+
shutil.rmtree(temp_dir);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
"""Override to use Vite bundling instead of simple concatenation."""
|
|
17
|
+
impl ViteClientBundleBuilder._compile_bundle(
|
|
18
|
+
self: ViteClientBundleBuilder, module: ModuleType, module_path: Path
|
|
19
|
+
) -> ClientBundle {
|
|
20
|
+
compiler = self._get_compiler();
|
|
21
|
+
(bundle_code, bundle_hash, client_exports, client_globals) = compiler.compile_and_bundle(
|
|
22
|
+
module, module_path
|
|
23
|
+
);
|
|
24
|
+
return ClientBundle(
|
|
25
|
+
module_name=module.__name__,
|
|
26
|
+
code=bundle_code,
|
|
27
|
+
client_functions=client_exports,
|
|
28
|
+
client_globals=client_globals,
|
|
29
|
+
hash=bundle_hash
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
"""Get or create the Vite compiler instance."""
|
|
34
|
+
impl ViteClientBundleBuilder._get_compiler(
|
|
35
|
+
self: ViteClientBundleBuilder
|
|
36
|
+
) -> ViteCompiler {
|
|
37
|
+
if (self._compiler is None) {
|
|
38
|
+
if (not self.vite_package_json or not self.vite_package_json.exists()) {
|
|
39
|
+
raise ClientBundleError(
|
|
40
|
+
'Vite package.json not found. Set vite_package_json when using ViteClientBundleBuilder'
|
|
41
|
+
) ;
|
|
42
|
+
}
|
|
43
|
+
compile_to_js_func: Callable[([Path], tuple[(str, (ModuleType | None))])] = cast(
|
|
44
|
+
Callable[([Path], tuple[(str, (ModuleType | None))])], self._compile_to_js
|
|
45
|
+
);
|
|
46
|
+
self._compiler = ViteCompiler(
|
|
47
|
+
vite_package_json=self.vite_package_json,
|
|
48
|
+
vite_output_dir=self.vite_output_dir,
|
|
49
|
+
vite_minify=self.vite_minify,
|
|
50
|
+
runtime_path=self.runtime_path,
|
|
51
|
+
compile_to_js_func=compile_to_js_func,
|
|
52
|
+
extract_exports_func=self._extract_client_exports,
|
|
53
|
+
extract_globals_func=self._extract_client_globals
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
return self._compiler;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
"""Initialize the Vite-enhanced bundle builder."""
|
|
60
|
+
impl ViteClientBundleBuilder.init(
|
|
61
|
+
self: ViteClientBundleBuilder,
|
|
62
|
+
runtime_path: (Path | None) = None,
|
|
63
|
+
vite_output_dir: (Path | None) = None,
|
|
64
|
+
vite_package_json: (Path | None) = None,
|
|
65
|
+
vite_minify: bool = False
|
|
66
|
+
) -> None {
|
|
67
|
+
super.init(runtime_path);
|
|
68
|
+
self.vite_output_dir = vite_output_dir;
|
|
69
|
+
self.vite_package_json = vite_package_json;
|
|
70
|
+
self.vite_minify = vite_minify;
|
|
71
|
+
self._compiler: (ViteCompiler | None) = None;
|
|
72
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"""Plugin configuration hooks for jac-client.
|
|
2
|
+
|
|
3
|
+
This module implements JacPluginConfig hooks to integrate with core's
|
|
4
|
+
configuration system, registering:
|
|
5
|
+
- Plugin metadata (name, version)
|
|
6
|
+
- Config schema for [plugins.client] section
|
|
7
|
+
- npm dependency type for [dependencies.npm] section
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import subprocess;
|
|
11
|
+
import sys;
|
|
12
|
+
import from pathlib { Path }
|
|
13
|
+
import from typing { Any }
|
|
14
|
+
import from jaclang.pycore.runtime { hookimpl }
|
|
15
|
+
import from jaclang.project.config { JacConfig }
|
|
16
|
+
|
|
17
|
+
"""Plugin configuration hooks for jac-client."""
|
|
18
|
+
class JacClientPluginConfig {
|
|
19
|
+
"""Return plugin metadata."""
|
|
20
|
+
@hookimpl
|
|
21
|
+
static def get_plugin_metadata -> dict[str, Any] {
|
|
22
|
+
return {
|
|
23
|
+
"name": "client",
|
|
24
|
+
"version": "1.0.0",
|
|
25
|
+
"description": "Jac client-side rendering with Vite bundling"
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
"""Return the plugin's configuration schema for [plugins.client]."""
|
|
30
|
+
@hookimpl
|
|
31
|
+
static def get_config_schema -> dict[str, Any] {
|
|
32
|
+
return {
|
|
33
|
+
"section": "client",
|
|
34
|
+
"options": {
|
|
35
|
+
"vite": {
|
|
36
|
+
"type": "dict",
|
|
37
|
+
"default": {},
|
|
38
|
+
"description": "Vite bundler configuration",
|
|
39
|
+
"nested": {
|
|
40
|
+
"plugins": {
|
|
41
|
+
"type": "list",
|
|
42
|
+
"default": [],
|
|
43
|
+
"description": "Vite plugins to include"
|
|
44
|
+
},
|
|
45
|
+
"lib_imports": {
|
|
46
|
+
"type": "list",
|
|
47
|
+
"default": [],
|
|
48
|
+
"description": "Library imports for vite.config.js"
|
|
49
|
+
},
|
|
50
|
+
"build": {
|
|
51
|
+
"type": "dict",
|
|
52
|
+
"default": {},
|
|
53
|
+
"description": "Vite build options"
|
|
54
|
+
},
|
|
55
|
+
"server": {
|
|
56
|
+
"type": "dict",
|
|
57
|
+
"default": {},
|
|
58
|
+
"description": "Vite dev server options"
|
|
59
|
+
},
|
|
60
|
+
"resolve": {
|
|
61
|
+
"type": "dict",
|
|
62
|
+
"default": {},
|
|
63
|
+
"description": "Vite resolve options"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"ts": {
|
|
68
|
+
"type": "dict",
|
|
69
|
+
"default": {},
|
|
70
|
+
"description": "TypeScript configuration overrides"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
"""Register npm as a dependency type for [dependencies.npm]."""
|
|
77
|
+
@hookimpl
|
|
78
|
+
static def register_dependency_type -> dict[str, Any] {
|
|
79
|
+
return {
|
|
80
|
+
"name": "npm",
|
|
81
|
+
"dev_name": "npm.dev",
|
|
82
|
+
"cli_flag": "--cl",
|
|
83
|
+
"install_dir": ".client-build/.jac-client.configs",
|
|
84
|
+
"install_handler": _npm_install_handler,
|
|
85
|
+
"install_all_handler": _npm_install_all_handler,
|
|
86
|
+
"remove_handler": _npm_remove_handler
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
"""Install an npm package."""
|
|
92
|
+
def _npm_install_handler(
|
|
93
|
+
config: JacConfig,
|
|
94
|
+
package_name: str,
|
|
95
|
+
version: str | None = None,
|
|
96
|
+
is_dev: bool = False
|
|
97
|
+
) -> None {
|
|
98
|
+
import from jac_client.plugin.src.vite_bundler { ViteBundler }
|
|
99
|
+
|
|
100
|
+
if config.project_root is None {
|
|
101
|
+
raise RuntimeError("No project root found") ;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
project_dir = config.project_root;
|
|
105
|
+
|
|
106
|
+
# Add to config (core JacConfig handles this)
|
|
107
|
+
package_version = version or "latest";
|
|
108
|
+
config.add_dependency(package_name, package_version, dev=is_dev, dep_type="npm");
|
|
109
|
+
config.save();
|
|
110
|
+
|
|
111
|
+
# Generate package.json and run npm install
|
|
112
|
+
_regenerate_and_install(project_dir);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
"""Install all npm packages from jac.toml."""
|
|
116
|
+
def _npm_install_all_handler(config: JacConfig) -> None {
|
|
117
|
+
if config.project_root is None {
|
|
118
|
+
raise RuntimeError("No project root found") ;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
_regenerate_and_install(config.project_root);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
"""Remove an npm package."""
|
|
125
|
+
def _npm_remove_handler(
|
|
126
|
+
config: JacConfig, package_name: str, is_dev: bool = False
|
|
127
|
+
) -> None {
|
|
128
|
+
if config.project_root is None {
|
|
129
|
+
raise RuntimeError("No project root found") ;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
project_dir = config.project_root;
|
|
133
|
+
|
|
134
|
+
# Remove from config (core JacConfig handles this)
|
|
135
|
+
result = config.remove_dependency(package_name, dev=is_dev, dep_type="npm");
|
|
136
|
+
if not result {
|
|
137
|
+
deps_key = "dev-dependencies" if is_dev else "dependencies";
|
|
138
|
+
raise RuntimeError(f'Package "{package_name}" not found in {deps_key}') ;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
config.save();
|
|
142
|
+
|
|
143
|
+
# Regenerate package.json and run npm install
|
|
144
|
+
_regenerate_and_install(project_dir);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
"""Regenerate package.json from jac.toml and run npm install."""
|
|
148
|
+
def _regenerate_and_install(project_dir: Path) -> None {
|
|
149
|
+
import from jac_client.plugin.src.vite_bundler { ViteBundler }
|
|
150
|
+
import shutil;
|
|
151
|
+
|
|
152
|
+
bundler = ViteBundler(project_dir);
|
|
153
|
+
bundler.create_package_json();
|
|
154
|
+
|
|
155
|
+
# Install to .client-build/ directory where babel processor expects it
|
|
156
|
+
build_dir = project_dir / '.client-build';
|
|
157
|
+
build_dir.mkdir(exist_ok=True);
|
|
158
|
+
|
|
159
|
+
# Copy package.json to .client-build/ for npm install
|
|
160
|
+
configs_package_json = build_dir / '.jac-client.configs' / 'package.json';
|
|
161
|
+
build_package_json = build_dir / 'package.json';
|
|
162
|
+
if configs_package_json.exists() {
|
|
163
|
+
shutil.copy2(configs_package_json, build_package_json);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
subprocess.run(
|
|
168
|
+
["npm", "install"],
|
|
169
|
+
cwd=build_dir,
|
|
170
|
+
check=True,
|
|
171
|
+
capture_output=True,
|
|
172
|
+
text=True
|
|
173
|
+
);
|
|
174
|
+
} except subprocess.CalledProcessError as e {
|
|
175
|
+
raise RuntimeError(f"Failed to install npm packages: {e.stderr}") from e ;
|
|
176
|
+
} except FileNotFoundError {
|
|
177
|
+
raise RuntimeError(
|
|
178
|
+
"npm command not found. Ensure Node.js and npm are installed."
|
|
179
|
+
) from None ;
|
|
180
|
+
} finally {
|
|
181
|
+
# Clean up temporary package.json
|
|
182
|
+
if build_package_json.exists() {
|
|
183
|
+
build_package_json.unlink();
|
|
184
|
+
}
|
|
185
|
+
# Move package-lock.json to .jac-client.configs/ if it exists
|
|
186
|
+
build_package_lock = build_dir / 'package-lock.json';
|
|
187
|
+
if build_package_lock.exists() {
|
|
188
|
+
configs_package_lock = build_dir / '.jac-client.configs' / 'package-lock.json';
|
|
189
|
+
if configs_package_lock.exists() {
|
|
190
|
+
configs_package_lock.unlink();
|
|
191
|
+
}
|
|
192
|
+
build_package_lock.rename(configs_package_lock);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Vite client bundle processing modules."""
|
|
2
|
+
import from jac_client.plugin.src.asset_processor { AssetProcessor }
|
|
3
|
+
import from jac_client.plugin.src.babel_processor { BabelProcessor }
|
|
4
|
+
import from jac_client.plugin.src.compiler { ViteCompiler }
|
|
5
|
+
import from jac_client.plugin.src.config_loader { JacClientConfig }
|
|
6
|
+
import from jac_client.plugin.src.import_processor { ImportProcessor }
|
|
7
|
+
import from jac_client.plugin.src.jac_to_js { JacToJSCompiler }
|
|
8
|
+
import from jac_client.plugin.src.package_installer { PackageInstaller }
|
|
9
|
+
import from jac_client.plugin.src.vite_bundler { ViteBundler }
|
|
10
|
+
|
|
11
|
+
glob __all__ = [
|
|
12
|
+
'AssetProcessor',
|
|
13
|
+
'BabelProcessor',
|
|
14
|
+
'ViteCompiler',
|
|
15
|
+
'JacClientConfig',
|
|
16
|
+
'ImportProcessor',
|
|
17
|
+
'JacToJSCompiler',
|
|
18
|
+
'ViteBundler',
|
|
19
|
+
'PackageInstaller'
|
|
20
|
+
];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Asset file processing and copying utilities."""
|
|
2
|
+
import contextlib;
|
|
3
|
+
import shutil;
|
|
4
|
+
import from pathlib { Path }
|
|
5
|
+
import from jaclang.project.config { get_config }
|
|
6
|
+
|
|
7
|
+
"""Handles copying of asset files (CSS, images, fonts, etc.) between directories."""
|
|
8
|
+
class AssetProcessor {
|
|
9
|
+
with entry {
|
|
10
|
+
ASSET_EXTENSIONS = {'.css','.scss','.sass','.less','.svg','.png','.jpg','.jpeg','.gif','.webp','.ico','.woff','.woff2','.ttf','.eot','.otf','.mp4','.webm','.mp3','.wav'};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
def copy_assets(
|
|
14
|
+
self: AssetProcessor,
|
|
15
|
+
src_dir: Path,
|
|
16
|
+
dest_dir: Path,
|
|
17
|
+
preserve_structure: bool = True
|
|
18
|
+
) -> None;
|
|
19
|
+
|
|
20
|
+
def copy_typescript_files(
|
|
21
|
+
self: AssetProcessor,
|
|
22
|
+
src_dir: Path,
|
|
23
|
+
dest_dir: Path,
|
|
24
|
+
preserve_structure: bool = True
|
|
25
|
+
) -> None;
|
|
26
|
+
|
|
27
|
+
def copy_custom_asset_types(
|
|
28
|
+
self: AssetProcessor,
|
|
29
|
+
src_dir: Path,
|
|
30
|
+
dest_dir: Path,
|
|
31
|
+
preserve_structure: bool = True
|
|
32
|
+
) -> None;
|
|
33
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Babel processing for JavaScript transpilation."""
|
|
2
|
+
import subprocess;
|
|
3
|
+
import from pathlib { Path }
|
|
4
|
+
import from jaclang.runtimelib.client_bundle { ClientBundleError }
|
|
5
|
+
import from .asset_processor { AssetProcessor }
|
|
6
|
+
import from .vite_bundler { ViteBundler }
|
|
7
|
+
|
|
8
|
+
"""Handles Babel compilation of JavaScript files."""
|
|
9
|
+
class BabelProcessor {
|
|
10
|
+
def init(self: BabelProcessor, project_dir: Path);
|
|
11
|
+
def compile(self: BabelProcessor) -> None;
|
|
12
|
+
def copy_assets_after_compile(
|
|
13
|
+
self: BabelProcessor,
|
|
14
|
+
compiled_dir: Path,
|
|
15
|
+
build_dir: Path,
|
|
16
|
+
asset_processor: AssetProcessor
|
|
17
|
+
) -> None;
|
|
18
|
+
}
|