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
|
@@ -57,12 +57,13 @@ impl JacClient.get_client_bundle_builder -> ViteClientBundleBuilder {
|
|
|
57
57
|
# Fallback to base_path_dir if no project root found
|
|
58
58
|
base_path = base_path_dir;
|
|
59
59
|
}
|
|
60
|
-
#
|
|
61
|
-
|
|
60
|
+
# Use ViteBundler to get the client directory
|
|
61
|
+
bundler = ViteBundler(base_path);
|
|
62
|
+
client_dir = bundler._get_client_dir();
|
|
63
|
+
# package.json should only exist in .jac/client/configs/
|
|
64
|
+
generated_package_json = client_dir / 'configs' / 'package.json';
|
|
62
65
|
# Generate package.json if it doesn't exist
|
|
63
66
|
if not generated_package_json.exists() {
|
|
64
|
-
# Use ViteBundler to generate package.json from config.json
|
|
65
|
-
bundler = ViteBundler(base_path);
|
|
66
67
|
generated_path = bundler.create_package_json();
|
|
67
68
|
# Verify the file was created and resolve to absolute path
|
|
68
69
|
if not generated_path.exists() {
|
|
@@ -80,7 +81,7 @@ impl JacClient.get_client_bundle_builder -> ViteClientBundleBuilder {
|
|
|
80
81
|
f'package.json not found at {package_json_path}. Expected at {generated_package_json}'
|
|
81
82
|
) ;
|
|
82
83
|
}
|
|
83
|
-
output_dir =
|
|
84
|
+
output_dir = client_dir / 'dist';
|
|
84
85
|
runtime_path = Path(__file__).with_name('client_runtime.cl.jac');
|
|
85
86
|
return ViteClientBundleBuilder(
|
|
86
87
|
runtime_path=runtime_path,
|
|
@@ -106,7 +107,7 @@ impl JacClientModuleIntrospector.render_page(
|
|
|
106
107
|
raise ValueError(f"Client function '{function_name}' not found") ;
|
|
107
108
|
}
|
|
108
109
|
bundle_hash = self.ensure_bundle();
|
|
109
|
-
import from jaclang.project.config { find_project_root }
|
|
110
|
+
import from jaclang.project.config { find_project_root, get_config }
|
|
110
111
|
# Find project root by looking for jac.toml (base_path_dir might be src/ for entry files)
|
|
111
112
|
base_path_dir = Path(Jac.base_path_dir);
|
|
112
113
|
project_root_result = find_project_root(base_path_dir);
|
|
@@ -116,16 +117,77 @@ impl JacClientModuleIntrospector.render_page(
|
|
|
116
117
|
# Fallback to base_path_dir if no project root found
|
|
117
118
|
base_path = base_path_dir;
|
|
118
119
|
}
|
|
119
|
-
|
|
120
|
+
# Get client directory from config or use default
|
|
121
|
+
config = get_config();
|
|
122
|
+
if config is not None {
|
|
123
|
+
dist_dir = config.get_client_dir() / 'dist';
|
|
124
|
+
} else {
|
|
125
|
+
dist_dir = base_path / '.jac' / 'client' / 'dist';
|
|
126
|
+
}
|
|
120
127
|
css_link = '';
|
|
121
|
-
css_file = dist_dir / '
|
|
128
|
+
css_file = dist_dir / 'styles.css';
|
|
122
129
|
if css_file.exists() {
|
|
123
130
|
css_hash = hashlib.sha256(css_file.read_bytes()).hexdigest()[:8];
|
|
124
|
-
css_link = f'<link rel="stylesheet" href="/static/
|
|
131
|
+
css_link = f'<link rel="stylesheet" href="/static/styles.css?hash={css_hash}"/>';
|
|
132
|
+
}
|
|
133
|
+
# Get meta data from config
|
|
134
|
+
client_cfg = config.get_plugin_config("client") if config else None;
|
|
135
|
+
meta_data = client_cfg.get("app_meta_data", {}) if client_cfg else {};
|
|
136
|
+
charset = meta_data.get("charset", "UTF-8");
|
|
137
|
+
title = meta_data.get("title", function_name);
|
|
138
|
+
viewport = meta_data.get("viewport", "width=device-width, initial-scale=1");
|
|
139
|
+
description = meta_data.get("description", None);
|
|
140
|
+
robots = meta_data.get("robots", "index, follow");
|
|
141
|
+
canonical = meta_data.get("canonical", None);
|
|
142
|
+
og_type = meta_data.get("og_type", "website");
|
|
143
|
+
og_title = meta_data.get("og_title", title);
|
|
144
|
+
og_description = meta_data.get("og_description", None);
|
|
145
|
+
og_url = meta_data.get("og_url", None);
|
|
146
|
+
og_image = meta_data.get("og_image", None);
|
|
147
|
+
theme_color = meta_data.get("theme_color", "#ffffff");
|
|
148
|
+
icon = meta_data.get("icon", None);
|
|
149
|
+
# Build head content from TOML metadata
|
|
150
|
+
head_content = f'<meta charset="{html.escape(charset)}"/>\n <meta name="viewport" content="{html.escape(
|
|
151
|
+
viewport
|
|
152
|
+
)}"/>\n <title>{html.escape(title)}</title>';
|
|
153
|
+
head_content += f'\n <meta name="robots" content="{html.escape(robots)}"/>';
|
|
154
|
+
head_content += f'\n <meta name="theme-color" content="{html.escape(
|
|
155
|
+
theme_color
|
|
156
|
+
)}"/>';
|
|
157
|
+
head_content += f'\n <meta property="og:type" content="{html.escape(
|
|
158
|
+
og_type
|
|
159
|
+
)}"/>';
|
|
160
|
+
head_content += f'\n <meta property="og:title" content="{html.escape(
|
|
161
|
+
og_title
|
|
162
|
+
)}"/>';
|
|
163
|
+
if description {
|
|
164
|
+
head_content += f'\n <meta name="description" content="{html.escape(
|
|
165
|
+
description
|
|
166
|
+
)}"/>';
|
|
167
|
+
}
|
|
168
|
+
if canonical {
|
|
169
|
+
head_content += f'\n <link rel="canonical" href="{html.escape(
|
|
170
|
+
canonical
|
|
171
|
+
)}"/>';
|
|
172
|
+
}
|
|
173
|
+
if icon {
|
|
174
|
+
head_content += f'\n <link rel="icon" href="{html.escape(icon)}"/>';
|
|
175
|
+
}
|
|
176
|
+
if og_url {
|
|
177
|
+
head_content += f'\n <meta property="og:url" content="{html.escape(
|
|
178
|
+
og_url
|
|
179
|
+
)}"/>';
|
|
180
|
+
}
|
|
181
|
+
if og_image {
|
|
182
|
+
head_content += f'\n <meta property="og:image" content="{html.escape(
|
|
183
|
+
og_image
|
|
184
|
+
)}"/>';
|
|
185
|
+
}
|
|
186
|
+
if og_description {
|
|
187
|
+
head_content += f'\n <meta property="og:description" content="{html.escape(
|
|
188
|
+
og_description
|
|
189
|
+
)}"/>';
|
|
125
190
|
}
|
|
126
|
-
head_content = f'<meta charset="utf-8"/>\n <title>{html.escape(
|
|
127
|
-
function_name
|
|
128
|
-
)}</title>';
|
|
129
191
|
if css_link {
|
|
130
192
|
head_content += f"\n {css_link}";
|
|
131
193
|
}
|
|
@@ -80,7 +80,7 @@ class JacClientPluginConfig {
|
|
|
80
80
|
"name": "npm",
|
|
81
81
|
"dev_name": "npm.dev",
|
|
82
82
|
"cli_flag": "--cl",
|
|
83
|
-
"install_dir": ".
|
|
83
|
+
"install_dir": ".jac/client/configs",
|
|
84
84
|
"install_handler": _npm_install_handler,
|
|
85
85
|
"install_all_handler": _npm_install_all_handler,
|
|
86
86
|
"remove_handler": _npm_remove_handler
|
|
@@ -152,13 +152,13 @@ def _regenerate_and_install(project_dir: Path) -> None {
|
|
|
152
152
|
bundler = ViteBundler(project_dir);
|
|
153
153
|
bundler.create_package_json();
|
|
154
154
|
|
|
155
|
-
# Install to .client
|
|
156
|
-
|
|
157
|
-
|
|
155
|
+
# Install to .jac/client/ directory where babel processor expects it
|
|
156
|
+
client_dir = bundler._get_client_dir();
|
|
157
|
+
client_dir.mkdir(parents=True, exist_ok=True);
|
|
158
158
|
|
|
159
|
-
# Copy package.json to .client
|
|
160
|
-
configs_package_json =
|
|
161
|
-
build_package_json =
|
|
159
|
+
# Copy package.json to .jac/client/ for npm install
|
|
160
|
+
configs_package_json = client_dir / 'configs' / 'package.json';
|
|
161
|
+
build_package_json = client_dir / 'package.json';
|
|
162
162
|
if configs_package_json.exists() {
|
|
163
163
|
shutil.copy2(configs_package_json, build_package_json);
|
|
164
164
|
}
|
|
@@ -166,7 +166,7 @@ def _regenerate_and_install(project_dir: Path) -> None {
|
|
|
166
166
|
try {
|
|
167
167
|
subprocess.run(
|
|
168
168
|
["npm", "install"],
|
|
169
|
-
cwd=
|
|
169
|
+
cwd=client_dir,
|
|
170
170
|
check=True,
|
|
171
171
|
capture_output=True,
|
|
172
172
|
text=True
|
|
@@ -182,10 +182,10 @@ def _regenerate_and_install(project_dir: Path) -> None {
|
|
|
182
182
|
if build_package_json.exists() {
|
|
183
183
|
build_package_json.unlink();
|
|
184
184
|
}
|
|
185
|
-
# Move package-lock.json to
|
|
186
|
-
build_package_lock =
|
|
185
|
+
# Move package-lock.json to configs/ if it exists
|
|
186
|
+
build_package_lock = client_dir / 'package-lock.json';
|
|
187
187
|
if build_package_lock.exists() {
|
|
188
|
-
configs_package_lock =
|
|
188
|
+
configs_package_lock = client_dir / 'configs' / 'package-lock.json';
|
|
189
189
|
if configs_package_lock.exists() {
|
|
190
190
|
configs_package_lock.unlink();
|
|
191
191
|
}
|
|
@@ -52,6 +52,7 @@ class ViteCompiler {
|
|
|
52
52
|
source_root: (Path | None) = None
|
|
53
53
|
) -> None;
|
|
54
54
|
|
|
55
|
+
def _get_client_dir(self: ViteCompiler) -> Path;
|
|
55
56
|
def _copy_js_file(self: ViteCompiler, js_path: Path, source_root: Path) -> None;
|
|
56
57
|
def _copy_ts_file(self: ViteCompiler, ts_path: Path, source_root: Path) -> None;
|
|
57
58
|
def _copy_asset_file(
|
|
@@ -59,7 +60,7 @@ class ViteCompiler {
|
|
|
59
60
|
) -> None;
|
|
60
61
|
|
|
61
62
|
def copy_root_assets(self: ViteCompiler) -> None;
|
|
62
|
-
def create_entry_file(self: ViteCompiler) -> None;
|
|
63
|
+
def create_entry_file(self: ViteCompiler, module_path: Path) -> None;
|
|
63
64
|
def compile_and_bundle(
|
|
64
65
|
self: ViteCompiler, module: ModuleType, module_path: Path
|
|
65
66
|
) -> tuple[str, str, list[str], list[str]];
|
|
@@ -17,21 +17,21 @@ impl BabelProcessor.compile(self: BabelProcessor) -> None {
|
|
|
17
17
|
bundler._ensure_root_package_json();
|
|
18
18
|
try {
|
|
19
19
|
# Ensure dependencies are installed (check if node_modules exists)
|
|
20
|
-
|
|
21
|
-
node_modules =
|
|
20
|
+
client_dir = bundler._get_client_dir();
|
|
21
|
+
node_modules = client_dir / 'node_modules';
|
|
22
22
|
if not node_modules.exists() {
|
|
23
|
-
# Temporarily copy package.json to .client
|
|
24
|
-
build_package_json =
|
|
25
|
-
configs_package_json =
|
|
23
|
+
# Temporarily copy package.json to .jac/client/ for npm install
|
|
24
|
+
build_package_json = client_dir / 'package.json';
|
|
25
|
+
configs_package_json = client_dir / 'configs' / 'package.json';
|
|
26
26
|
if configs_package_json.exists() and not build_package_json.exists() {
|
|
27
27
|
import shutil;
|
|
28
28
|
shutil.copy2(configs_package_json, build_package_json);
|
|
29
29
|
}
|
|
30
30
|
try {
|
|
31
|
-
# Install to .client
|
|
31
|
+
# Install to .jac/client/node_modules
|
|
32
32
|
subprocess.run(
|
|
33
33
|
['npm', 'install'],
|
|
34
|
-
cwd=
|
|
34
|
+
cwd=client_dir,
|
|
35
35
|
check=True,
|
|
36
36
|
capture_output=True,
|
|
37
37
|
text=True
|
|
@@ -47,27 +47,32 @@ impl BabelProcessor.compile(self: BabelProcessor) -> None {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
# Temporarily copy package.json to .client
|
|
51
|
-
build_package_json =
|
|
52
|
-
configs_package_json =
|
|
50
|
+
# Temporarily copy package.json to .jac/client/ for npm run compile
|
|
51
|
+
build_package_json = client_dir / 'package.json';
|
|
52
|
+
configs_package_json = client_dir / 'configs' / 'package.json';
|
|
53
53
|
if configs_package_json.exists() and not build_package_json.exists() {
|
|
54
54
|
import shutil;
|
|
55
55
|
shutil.copy2(configs_package_json, build_package_json);
|
|
56
56
|
}
|
|
57
57
|
command = ['npm', 'run', 'compile'];
|
|
58
|
-
subprocess.run(
|
|
59
|
-
command, cwd=
|
|
58
|
+
result = subprocess.run(
|
|
59
|
+
command, cwd=client_dir, capture_output=True, text=True
|
|
60
60
|
);
|
|
61
|
+
if result.returncode != 0 {
|
|
62
|
+
# Show the actual error from npm/babel
|
|
63
|
+
error_output = result.stderr or result.stdout or "Unknown error";
|
|
64
|
+
raise RuntimeError(f"Client bundle compilation failed:\n{error_output}") ;
|
|
65
|
+
}
|
|
61
66
|
} finally {
|
|
62
|
-
# Clean up temporary package.json in .client
|
|
63
|
-
build_package_json =
|
|
67
|
+
# Clean up temporary package.json in .jac/client/
|
|
68
|
+
build_package_json = client_dir / 'package.json';
|
|
64
69
|
if build_package_json.exists() {
|
|
65
70
|
build_package_json.unlink();
|
|
66
71
|
}
|
|
67
|
-
# Move package-lock.json to
|
|
68
|
-
build_package_lock =
|
|
72
|
+
# Move package-lock.json to configs/ if it exists
|
|
73
|
+
build_package_lock = client_dir / 'package-lock.json';
|
|
69
74
|
if build_package_lock.exists() {
|
|
70
|
-
configs_package_lock =
|
|
75
|
+
configs_package_lock = client_dir / 'configs' / 'package-lock.json';
|
|
71
76
|
if configs_package_lock.exists() {
|
|
72
77
|
configs_package_lock.unlink();
|
|
73
78
|
}
|
|
@@ -1,5 +1,20 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Get the client build directory from project config."""
|
|
2
|
+
impl ViteCompiler._get_client_dir(self: ViteCompiler) -> Path {
|
|
3
|
+
# Try to get from project config
|
|
4
|
+
try {
|
|
5
|
+
import from jaclang.project.config { get_config }
|
|
6
|
+
config = get_config();
|
|
7
|
+
if config is not None {
|
|
8
|
+
return config.get_client_dir();
|
|
9
|
+
}
|
|
10
|
+
} except ImportError {
|
|
11
|
+
pass;
|
|
12
|
+
}
|
|
13
|
+
# Fallback to default
|
|
14
|
+
return self.project_dir / '.jac' / 'client';
|
|
15
|
+
}
|
|
2
16
|
|
|
17
|
+
"""Compile module and dependencies, then bundle with Vite."""
|
|
3
18
|
impl ViteCompiler.compile_and_bundle(
|
|
4
19
|
self: ViteCompiler, module: ModuleType, module_path: Path
|
|
5
20
|
) -> tuple[str, str, list[str], list[str]] {
|
|
@@ -16,14 +31,13 @@ impl ViteCompiler.compile_and_bundle(
|
|
|
16
31
|
collected_globals=collected_globals
|
|
17
32
|
);
|
|
18
33
|
self.copy_root_assets();
|
|
19
|
-
self.create_entry_file();
|
|
34
|
+
self.create_entry_file(module_path);
|
|
20
35
|
self.babel_processor.compile();
|
|
36
|
+
client_dir = self._get_client_dir();
|
|
21
37
|
self.babel_processor.copy_assets_after_compile(
|
|
22
|
-
self.compiled_dir,
|
|
23
|
-
(self.project_dir / '.client-build' / 'build'),
|
|
24
|
-
self.asset_processor
|
|
38
|
+
self.compiled_dir, (client_dir / 'build'), self.asset_processor
|
|
25
39
|
);
|
|
26
|
-
entry_file =
|
|
40
|
+
entry_file = client_dir / 'build' / '_entry.js';
|
|
27
41
|
self.vite_bundler.build(entry_file=entry_file);
|
|
28
42
|
(bundle_code, bundle_hash) = self.vite_bundler.read_bundle();
|
|
29
43
|
client_exports = sorted(collected_exports);
|
|
@@ -32,9 +46,12 @@ impl ViteCompiler.compile_and_bundle(
|
|
|
32
46
|
}
|
|
33
47
|
|
|
34
48
|
"""Create the main entry file for Vite bundling."""
|
|
35
|
-
impl ViteCompiler.create_entry_file(self: ViteCompiler) -> None {
|
|
36
|
-
|
|
37
|
-
|
|
49
|
+
impl ViteCompiler.create_entry_file(self: ViteCompiler, module_path: Path) -> None {
|
|
50
|
+
# Use _entry.js to avoid conflict with compiled modules that may be named main.js
|
|
51
|
+
entry_file = self.compiled_dir / '_entry.js';
|
|
52
|
+
# Derive the app module filename from the entry point (e.g., main.jac -> main.js, app.jac -> app.js)
|
|
53
|
+
app_module_name = module_path.stem;
|
|
54
|
+
entry_content = f'import React from "react";\nimport {{ createRoot }} from "react-dom/client";\nimport {{ app as App }} from "./{app_module_name}.js";\n\nconst root = createRoot(document.getElementById("root"));\nroot.render(<App />);\n';
|
|
38
55
|
entry_file.write_text(entry_content, encoding='utf-8');
|
|
39
56
|
}
|
|
40
57
|
|
|
@@ -46,7 +63,7 @@ impl ViteCompiler.copy_root_assets(self: ViteCompiler) -> None {
|
|
|
46
63
|
self.asset_processor.copy_assets(root_assets_dir, compiled_assets_dir);
|
|
47
64
|
}
|
|
48
65
|
# Copy configured_asset files from root assets/ to build assets/ (bypassing compiled)
|
|
49
|
-
build_assets_dir = self.
|
|
66
|
+
build_assets_dir = self._get_client_dir() / 'build' / 'assets';
|
|
50
67
|
if (root_assets_dir.exists() and root_assets_dir.is_dir()) {
|
|
51
68
|
self.asset_processor.copy_custom_asset_types(root_assets_dir, build_assets_dir);
|
|
52
69
|
}
|
|
@@ -149,9 +166,29 @@ impl ViteCompiler.compile_dependencies_recursively(
|
|
|
149
166
|
combined_js = self.jac_compiler.add_runtime_imports(module_js);
|
|
150
167
|
try {
|
|
151
168
|
relative_path = module_path.relative_to(source_root);
|
|
152
|
-
|
|
169
|
+
# Handle compound extensions like .cl.jac, .impl.jac -> .js
|
|
170
|
+
rel_str = str(relative_path);
|
|
171
|
+
for compound_ext in ['.cl.jac', '.impl.jac', '.test.jac'] {
|
|
172
|
+
if rel_str.endswith(compound_ext) {
|
|
173
|
+
rel_str = rel_str[:-len(compound_ext)] + '.js';
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
rel_str = str(relative_path.with_suffix('.js'));
|
|
178
|
+
}
|
|
179
|
+
output_path = self.compiled_dir / rel_str;
|
|
153
180
|
} except ValueError {
|
|
154
|
-
|
|
181
|
+
# Handle compound extensions in filename
|
|
182
|
+
name = module_path.name;
|
|
183
|
+
for compound_ext in ['.cl.jac', '.impl.jac', '.test.jac'] {
|
|
184
|
+
if name.endswith(compound_ext) {
|
|
185
|
+
name = name[:-len(compound_ext)] + '.js';
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
name = module_path.stem + '.js';
|
|
190
|
+
}
|
|
191
|
+
output_path = self.compiled_dir / name;
|
|
155
192
|
}
|
|
156
193
|
output_path.parent.mkdir(parents=True, exist_ok=True);
|
|
157
194
|
output_path.write_text(combined_js, encoding='utf-8');
|
|
@@ -228,19 +265,21 @@ impl ViteCompiler.init(
|
|
|
228
265
|
) ;
|
|
229
266
|
}
|
|
230
267
|
self.vite_package_json = vite_package_json;
|
|
231
|
-
#
|
|
268
|
+
# Detect project root: package.json may be in .jac/client/configs/ or project root
|
|
232
269
|
if (
|
|
233
|
-
vite_package_json.parent.name == '
|
|
234
|
-
and vite_package_json.parent.parent.name == '
|
|
270
|
+
vite_package_json.parent.name == 'configs'
|
|
271
|
+
and vite_package_json.parent.parent.name == 'client'
|
|
272
|
+
and vite_package_json.parent.parent.parent.name == '.jac'
|
|
235
273
|
) {
|
|
236
|
-
|
|
237
|
-
|
|
274
|
+
# .jac/client/configs/package.json -> go up 3 levels to project root
|
|
275
|
+
self.project_dir = vite_package_json.parent.parent.parent.parent;
|
|
276
|
+
} elif (vite_package_json.parent.name == 'configs') {
|
|
238
277
|
self.project_dir = vite_package_json.parent.parent;
|
|
239
278
|
} else {
|
|
240
279
|
self.project_dir = vite_package_json.parent;
|
|
241
280
|
}
|
|
242
281
|
self.runtime_path = runtime_path;
|
|
243
|
-
self.compiled_dir = self.
|
|
282
|
+
self.compiled_dir = self._get_client_dir() / 'compiled';
|
|
244
283
|
self.jac_compiler = JacToJSCompiler(
|
|
245
284
|
compile_to_js_func, extract_exports_func, extract_globals_func
|
|
246
285
|
);
|