jac-client 0.2.6__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.6.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.6.dist-info/RECORD +0 -74
- {jac_client-0.2.6.dist-info → jac_client-0.2.7.dist-info}/WHEEL +0 -0
- {jac_client-0.2.6.dist-info → jac_client-0.2.7.dist-info}/entry_points.txt +0 -0
- {jac_client-0.2.6.dist-info → jac_client-0.2.7.dist-info}/top_level.txt +0 -0
|
@@ -1,11 +1,26 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Get the client build directory from project config."""
|
|
2
|
+
impl ViteBundler._get_client_dir(self: ViteBundler) -> 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
|
+
"""Create package.json from config.json during bundling."""
|
|
3
18
|
impl ViteBundler.create_package_json(
|
|
4
19
|
self: ViteBundler, project_name: Optional[str] = None
|
|
5
20
|
) -> Path {
|
|
6
|
-
build_dir = self.
|
|
7
|
-
build_dir.mkdir(exist_ok=True);
|
|
8
|
-
configs_dir = build_dir / '
|
|
21
|
+
build_dir = self._get_client_dir();
|
|
22
|
+
build_dir.mkdir(parents=True, exist_ok=True);
|
|
23
|
+
configs_dir = build_dir / 'configs';
|
|
9
24
|
configs_dir.mkdir(exist_ok=True);
|
|
10
25
|
package_config = self.config_loader.get_package_config();
|
|
11
26
|
package_json_path = configs_dir / 'package.json';
|
|
@@ -29,32 +44,12 @@ impl ViteBundler.create_package_json(
|
|
|
29
44
|
if not name {
|
|
30
45
|
name = self.project_dir.name or 'jac-app';
|
|
31
46
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
'react': '^18.2.0',
|
|
35
|
-
'react-dom': '^18.2.0',
|
|
36
|
-
'react-router-dom': '^6.22.0'
|
|
37
|
-
};
|
|
38
|
-
default_dev_dependencies = {
|
|
39
|
-
'vite': '^6.4.1',
|
|
40
|
-
'@babel/cli': '^7.28.3',
|
|
41
|
-
'@babel/core': '^7.28.5',
|
|
42
|
-
'@babel/preset-env': '^7.28.5',
|
|
43
|
-
'@babel/preset-react': '^7.28.5',
|
|
44
|
-
'@vitejs/plugin-react': '^4.2.1',
|
|
45
|
-
'typescript': '^5.3.3',
|
|
46
|
-
'@types/react': '^18.2.0',
|
|
47
|
-
'@types/react-dom': '^18.2.0'
|
|
48
|
-
};
|
|
49
|
-
# Merge user dependencies from TOML with defaults (user can override)
|
|
50
|
-
user_dependencies = package_config.get('dependencies', {});
|
|
51
|
-
user_dev_dependencies = package_config.get('devDependencies', {});
|
|
52
|
-
dependencies = {** default_dependencies, ** user_dependencies};
|
|
53
|
-
dev_dependencies = {** default_dev_dependencies, ** user_dev_dependencies};
|
|
47
|
+
dependencies = package_config.get('dependencies', {});
|
|
48
|
+
dev_dependencies = package_config.get('devDependencies', {});
|
|
54
49
|
scripts = {
|
|
55
|
-
'build': 'npm run compile && vite build --config .
|
|
56
|
-
'dev': 'vite dev --config .
|
|
57
|
-
'preview': 'vite preview --config .
|
|
50
|
+
'build': 'npm run compile && vite build --config .jac/client/configs/vite.config.js',
|
|
51
|
+
'dev': 'vite dev --config .jac/client/configs/vite.config.js',
|
|
52
|
+
'preview': 'vite preview --config .jac/client/configs/vite.config.js',
|
|
58
53
|
'compile': 'babel compiled --out-dir build --extensions ".jsx,.js" --out-file-extension .js'
|
|
59
54
|
};
|
|
60
55
|
user_scripts = package_config.get('scripts', {});
|
|
@@ -90,9 +85,9 @@ impl ViteBundler.create_package_json(
|
|
|
90
85
|
|
|
91
86
|
"""Create tsconfig.json during build time, merging user config from jac.toml."""
|
|
92
87
|
impl ViteBundler.create_tsconfig(self: ViteBundler) -> Path {
|
|
93
|
-
build_dir = self.
|
|
94
|
-
build_dir.mkdir(exist_ok=True);
|
|
95
|
-
configs_dir = build_dir / '
|
|
88
|
+
build_dir = self._get_client_dir();
|
|
89
|
+
build_dir.mkdir(parents=True, exist_ok=True);
|
|
90
|
+
configs_dir = build_dir / 'configs';
|
|
96
91
|
configs_dir.mkdir(exist_ok=True);
|
|
97
92
|
tsconfig_path = configs_dir / 'tsconfig.json';
|
|
98
93
|
# Default tsconfig settings
|
|
@@ -114,7 +109,7 @@ impl ViteBundler.create_tsconfig(self: ViteBundler) -> Path {
|
|
|
114
109
|
'noFallthroughCasesInSwitch': True
|
|
115
110
|
};
|
|
116
111
|
default_include = ['components/**/*'];
|
|
117
|
-
default_exclude = ['.
|
|
112
|
+
default_exclude = ['.jac'];
|
|
118
113
|
# Get user config from [plugins.client.ts] in jac.toml
|
|
119
114
|
user_ts_config = self.config_loader.get_ts_config();
|
|
120
115
|
user_compiler_options = user_ts_config.get('compilerOptions', {});
|
|
@@ -130,21 +125,21 @@ impl ViteBundler.create_tsconfig(self: ViteBundler) -> Path {
|
|
|
130
125
|
'include': merged_include,
|
|
131
126
|
'exclude': merged_exclude
|
|
132
127
|
};
|
|
133
|
-
# Write the config to .
|
|
128
|
+
# Write the config to .jac/client/configs/tsconfig.json (no root config file)
|
|
134
129
|
tsconfig_path.write_text(json.dumps(tsconfig_data, indent=2), encoding='utf-8');
|
|
135
130
|
return tsconfig_path;
|
|
136
131
|
}
|
|
137
132
|
|
|
138
133
|
"""
|
|
139
|
-
Clean up root package.json and move package-lock.json to
|
|
134
|
+
Clean up root package.json and move package-lock.json to configs/.
|
|
140
135
|
|
|
141
|
-
Remove root package.json and move package-lock.json to
|
|
136
|
+
Remove root package.json and move package-lock.json to configs/.
|
|
142
137
|
"""
|
|
143
138
|
impl ViteBundler._cleanup_root_package_files(self: ViteBundler) -> None {
|
|
144
139
|
root_package_json = self.project_dir / 'package.json';
|
|
145
140
|
root_package_lock = self.project_dir / 'package-lock.json';
|
|
146
|
-
build_dir = self.
|
|
147
|
-
configs_dir = build_dir / '
|
|
141
|
+
build_dir = self._get_client_dir();
|
|
142
|
+
configs_dir = build_dir / 'configs';
|
|
148
143
|
configs_package_lock = configs_dir / 'package-lock.json';
|
|
149
144
|
if root_package_lock.exists() {
|
|
150
145
|
configs_dir.mkdir(exist_ok=True);
|
|
@@ -164,7 +159,7 @@ Ensure root package.json exists temporarily for npm commands.
|
|
|
164
159
|
Create root package.json temporarily if it doesn't exist.
|
|
165
160
|
"""
|
|
166
161
|
impl ViteBundler._ensure_root_package_json(self: ViteBundler) -> None {
|
|
167
|
-
generated_package_json = self.
|
|
162
|
+
generated_package_json = self._get_client_dir() / 'configs' / 'package.json';
|
|
168
163
|
root_package_json = self.project_dir / 'package.json';
|
|
169
164
|
if not generated_package_json.exists() {
|
|
170
165
|
self.create_package_json();
|
|
@@ -235,51 +230,28 @@ impl ViteBundler._get_plugin_var_name(self: ViteBundler, plugin_name: str) -> st
|
|
|
235
230
|
|
|
236
231
|
"""Create vite.config.js from config.json during bundling."""
|
|
237
232
|
impl ViteBundler.create_vite_config(self: ViteBundler, entry_file: Path) -> Path {
|
|
238
|
-
build_dir = self.
|
|
239
|
-
build_dir.mkdir(exist_ok=True);
|
|
240
|
-
configs_dir = build_dir / '
|
|
233
|
+
build_dir = self._get_client_dir();
|
|
234
|
+
build_dir.mkdir(parents=True, exist_ok=True);
|
|
235
|
+
configs_dir = build_dir / 'configs';
|
|
241
236
|
configs_dir.mkdir(exist_ok=True);
|
|
242
237
|
vite_config_data = self.config_loader.get_vite_config();
|
|
243
238
|
config_path = configs_dir / 'vite.config.js';
|
|
244
239
|
# TypeScript is always enabled by default
|
|
245
|
-
build_dir = self.project_dir / '.client-build';
|
|
246
240
|
try {
|
|
247
|
-
# Entry file path relative to
|
|
241
|
+
# Entry file path relative to client build dir (not project root)
|
|
248
242
|
entry_relative = entry_file.relative_to(build_dir).as_posix();
|
|
249
243
|
} except ValueError {
|
|
250
|
-
# Fallback:
|
|
251
|
-
|
|
252
|
-
entry_relative_full = entry_file.relative_to(self.project_dir).as_posix();
|
|
253
|
-
prefix = '.client-build/';
|
|
254
|
-
if entry_relative_full.startswith(prefix) {
|
|
255
|
-
# Remove '.client-build/' prefix (15 characters)
|
|
256
|
-
entry_relative = entry_relative_full[15:];
|
|
257
|
-
} else {
|
|
258
|
-
entry_relative = entry_relative_full;
|
|
259
|
-
}
|
|
260
|
-
} except ValueError {
|
|
261
|
-
entry_relative = entry_file.as_posix();
|
|
262
|
-
}
|
|
244
|
+
# Fallback: use absolute path
|
|
245
|
+
entry_relative = entry_file.as_posix();
|
|
263
246
|
}
|
|
264
247
|
try {
|
|
265
|
-
# Output dir path relative to
|
|
248
|
+
# Output dir path relative to client build dir (not project root)
|
|
266
249
|
output_relative = self.output_dir.relative_to(build_dir).as_posix();
|
|
267
250
|
} except ValueError {
|
|
268
|
-
# Fallback:
|
|
269
|
-
|
|
270
|
-
output_relative_full = self.output_dir.relative_to(self.project_dir).as_posix();
|
|
271
|
-
prefix = '.client-build/';
|
|
272
|
-
if output_relative_full.startswith(prefix) {
|
|
273
|
-
# Remove '.client-build/' prefix (15 characters)
|
|
274
|
-
output_relative = output_relative_full[15:];
|
|
275
|
-
} else {
|
|
276
|
-
output_relative = output_relative_full;
|
|
277
|
-
}
|
|
278
|
-
} except ValueError {
|
|
279
|
-
output_relative = self.output_dir.as_posix();
|
|
280
|
-
}
|
|
251
|
+
# Fallback: use absolute path
|
|
252
|
+
output_relative = self.output_dir.as_posix();
|
|
281
253
|
}
|
|
282
|
-
# Calculate compiled directory path for aliases (relative to
|
|
254
|
+
# Calculate compiled directory path for aliases (relative to client build dir)
|
|
283
255
|
if entry_relative.endswith('/build/main.js') {
|
|
284
256
|
compiled_utils_relative = entry_relative[:-13] + '/compiled/client_runtime.js';
|
|
285
257
|
compiled_assets_relative = entry_relative[:-13] + '/compiled/assets';
|
|
@@ -333,9 +305,9 @@ impl ViteBundler.create_vite_config(self: ViteBundler, entry_file: Path) -> Path
|
|
|
333
305
|
import path from "path";
|
|
334
306
|
import {{ fileURLToPath }} from "url";
|
|
335
307
|
{imports_section}const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
336
|
-
// Config is in
|
|
308
|
+
// Config is in configs/ inside .jac/client/, so go up one level to .jac/client/, then up two more to project root
|
|
337
309
|
const buildDir = path.resolve(__dirname, "..");
|
|
338
|
-
const projectRoot = path.resolve(__dirname, "
|
|
310
|
+
const projectRoot = path.resolve(__dirname, "../../..");
|
|
339
311
|
|
|
340
312
|
/**
|
|
341
313
|
* Vite configuration generated from config.json (in project root)
|
|
@@ -344,13 +316,13 @@ const projectRoot = path.resolve(__dirname, "../..");
|
|
|
344
316
|
|
|
345
317
|
export default defineConfig({{
|
|
346
318
|
plugins: [{(newline + plugins_str + newline + ' ') if plugins_str else ''}],
|
|
347
|
-
root: buildDir, // base folder (.client
|
|
319
|
+
root: buildDir, // base folder (.jac/client/) so vite can find node_modules
|
|
348
320
|
build: {{
|
|
349
321
|
rollupOptions: {{
|
|
350
322
|
input: path.resolve(buildDir, "{entry_relative}"), // your compiled entry file
|
|
351
323
|
output: {{
|
|
352
324
|
entryFileNames: "client.[hash].js", // name of the final js file
|
|
353
|
-
assetFileNames:
|
|
325
|
+
assetFileNames: (assetInfo) => assetInfo.name?.endsWith('.css') ? 'styles.css' : '[name].[ext]',
|
|
354
326
|
}},
|
|
355
327
|
}},
|
|
356
328
|
outDir: path.resolve(buildDir, "{output_relative}"), // final bundled output
|
|
@@ -391,14 +363,8 @@ impl ViteBundler.read_bundle(self: ViteBundler) -> tuple[str, str] {
|
|
|
391
363
|
|
|
392
364
|
"""Find the generated Vite CSS file."""
|
|
393
365
|
impl ViteBundler.find_css(self: ViteBundler) -> Optional[Path] {
|
|
394
|
-
css_file = self.output_dir / '
|
|
395
|
-
if css_file.exists()
|
|
396
|
-
return css_file;
|
|
397
|
-
}
|
|
398
|
-
for file in self.output_dir.glob('*.css') {
|
|
399
|
-
return file;
|
|
400
|
-
}
|
|
401
|
-
return None;
|
|
366
|
+
css_file = self.output_dir / 'styles.css';
|
|
367
|
+
return css_file if css_file.exists() else None;
|
|
402
368
|
}
|
|
403
369
|
|
|
404
370
|
"""Find the generated Vite bundle file."""
|
|
@@ -409,10 +375,10 @@ impl ViteBundler.find_bundle(self: ViteBundler) -> Optional[Path] {
|
|
|
409
375
|
return None;
|
|
410
376
|
}
|
|
411
377
|
|
|
412
|
-
"""Run Vite build with generated config in .
|
|
378
|
+
"""Run Vite build with generated config in .jac/client/configs/."""
|
|
413
379
|
impl ViteBundler.build(self: ViteBundler, entry_file: Optional[Path] = None) -> None {
|
|
414
380
|
self.output_dir.mkdir(parents=True, exist_ok=True);
|
|
415
|
-
generated_package_json = self.
|
|
381
|
+
generated_package_json = self._get_client_dir() / 'configs' / 'package.json';
|
|
416
382
|
if not generated_package_json.exists() {
|
|
417
383
|
self.create_package_json();
|
|
418
384
|
} else {
|
|
@@ -420,18 +386,18 @@ impl ViteBundler.build(self: ViteBundler, entry_file: Optional[Path] = None) ->
|
|
|
420
386
|
self.create_tsconfig();
|
|
421
387
|
}
|
|
422
388
|
try {
|
|
423
|
-
build_dir = self.
|
|
389
|
+
build_dir = self._get_client_dir();
|
|
424
390
|
node_modules = build_dir / 'node_modules';
|
|
425
391
|
if not node_modules.exists() {
|
|
426
|
-
# Temporarily copy package.json to
|
|
392
|
+
# Temporarily copy package.json to client build dir for npm install
|
|
427
393
|
build_package_json = build_dir / 'package.json';
|
|
428
|
-
configs_package_json = build_dir / '
|
|
394
|
+
configs_package_json = build_dir / 'configs' / 'package.json';
|
|
429
395
|
if configs_package_json.exists() and not build_package_json.exists() {
|
|
430
396
|
import shutil;
|
|
431
397
|
shutil.copy2(configs_package_json, build_package_json);
|
|
432
398
|
}
|
|
433
399
|
try {
|
|
434
|
-
# Install to .client
|
|
400
|
+
# Install to .jac/client/node_modules
|
|
435
401
|
subprocess.run(
|
|
436
402
|
['npm', 'install'],
|
|
437
403
|
cwd=build_dir,
|
|
@@ -449,27 +415,24 @@ impl ViteBundler.build(self: ViteBundler, entry_file: Optional[Path] = None) ->
|
|
|
449
415
|
) ;
|
|
450
416
|
}
|
|
451
417
|
}
|
|
452
|
-
build_dir = self.project_dir / '.client-build';
|
|
453
418
|
if self.config_path {
|
|
454
419
|
# Make config path relative to build_dir (where vite runs from)
|
|
455
|
-
|
|
456
|
-
if '.client-build' in config_str {
|
|
457
|
-
# Config is in .client-build/, make it relative to build_dir
|
|
420
|
+
try {
|
|
458
421
|
config_rel = self.config_path.relative_to(build_dir);
|
|
459
422
|
command = ['npx', 'vite', 'build', '--config', str(config_rel)];
|
|
460
|
-
}
|
|
461
|
-
# Config is outside
|
|
423
|
+
} except ValueError {
|
|
424
|
+
# Config is outside client build dir, use absolute path
|
|
462
425
|
command = ['npx', 'vite', 'build', '--config', str(self.config_path)];
|
|
463
426
|
}
|
|
464
427
|
} elif entry_file {
|
|
465
428
|
generated_config = self.create_vite_config(entry_file);
|
|
466
|
-
# Config is in
|
|
429
|
+
# Config is in configs/, make it relative to build_dir
|
|
467
430
|
config_rel = generated_config.relative_to(build_dir);
|
|
468
431
|
command = ['npx', 'vite', 'build', '--config', str(config_rel)];
|
|
469
432
|
} else {
|
|
470
433
|
command = ['npm', 'run', 'build'];
|
|
471
434
|
}
|
|
472
|
-
# Run vite from
|
|
435
|
+
# Run vite from client build directory so it can find node_modules
|
|
473
436
|
result = subprocess.run(
|
|
474
437
|
command, cwd=build_dir, check=False, capture_output=True, text=True
|
|
475
438
|
);
|
|
@@ -480,15 +443,15 @@ impl ViteBundler.build(self: ViteBundler, entry_file: Optional[Path] = None) ->
|
|
|
480
443
|
) from None ;
|
|
481
444
|
}
|
|
482
445
|
} finally {
|
|
483
|
-
# Clean up temporary package.json in
|
|
446
|
+
# Clean up temporary package.json in client build dir
|
|
484
447
|
build_package_json = build_dir / 'package.json';
|
|
485
448
|
if build_package_json.exists() {
|
|
486
449
|
build_package_json.unlink();
|
|
487
450
|
}
|
|
488
|
-
# Move package-lock.json to
|
|
451
|
+
# Move package-lock.json to configs/ if it exists
|
|
489
452
|
build_package_lock = build_dir / 'package-lock.json';
|
|
490
453
|
if build_package_lock.exists() {
|
|
491
|
-
configs_package_lock = build_dir / '
|
|
454
|
+
configs_package_lock = build_dir / 'configs' / 'package-lock.json';
|
|
492
455
|
if configs_package_lock.exists() {
|
|
493
456
|
configs_package_lock.unlink();
|
|
494
457
|
}
|
|
@@ -506,8 +469,9 @@ impl ViteBundler.init(
|
|
|
506
469
|
config_path: Optional[Path] = None
|
|
507
470
|
) {
|
|
508
471
|
self.project_dir = project_dir;
|
|
509
|
-
self.output_dir = output_dir or (project_dir / '.client-build' / 'dist');
|
|
510
472
|
self.minify = minify;
|
|
511
473
|
self.config_path = config_path;
|
|
512
474
|
self.config_loader = JacClientConfig(project_dir);
|
|
475
|
+
# Set output_dir after config_loader is initialized so _get_client_dir works
|
|
476
|
+
self.output_dir = output_dir or (self._get_client_dir() / 'dist');
|
|
513
477
|
}
|
|
@@ -17,6 +17,7 @@ class ViteBundler {
|
|
|
17
17
|
config_path: Optional[Path] = None
|
|
18
18
|
);
|
|
19
19
|
|
|
20
|
+
def _get_client_dir(self: ViteBundler) -> Path;
|
|
20
21
|
def build(self: ViteBundler, entry_file: Optional[Path] = None) -> None;
|
|
21
22
|
def find_bundle(self: ViteBundler) -> Optional[Path];
|
|
22
23
|
def find_css(self: ViteBundler) -> Optional[Path];
|
jac_client/tests/conftest.py
CHANGED
|
@@ -108,7 +108,7 @@ def npm_cache_dir() -> Generator[Path, None, None]:
|
|
|
108
108
|
"""Session-scoped fixture that provides a directory with npm packages installed.
|
|
109
109
|
|
|
110
110
|
This runs npm install once per test session and provides the path to the
|
|
111
|
-
.jac
|
|
111
|
+
.jac/client/configs directory containing node_modules.
|
|
112
112
|
"""
|
|
113
113
|
global _npm_cache_dir
|
|
114
114
|
|
|
@@ -156,13 +156,14 @@ def vite_project_dir(npm_cache_dir: Path, tmp_path: Path) -> Path:
|
|
|
156
156
|
jac_toml = tmp_path / "jac.toml"
|
|
157
157
|
jac_toml.write_text(_get_minimal_jac_toml())
|
|
158
158
|
|
|
159
|
-
# Copy .jac
|
|
160
|
-
source_configs = npm_cache_dir / ".jac
|
|
161
|
-
dest_configs = tmp_path / ".jac
|
|
159
|
+
# Copy .jac/client/configs directory (contains package.json)
|
|
160
|
+
source_configs = npm_cache_dir / ".jac" / "client" / "configs"
|
|
161
|
+
dest_configs = tmp_path / ".jac" / "client" / "configs"
|
|
162
162
|
if source_configs.exists():
|
|
163
|
+
dest_configs.parent.mkdir(parents=True, exist_ok=True)
|
|
163
164
|
shutil.copytree(source_configs, dest_configs, symlinks=True)
|
|
164
165
|
|
|
165
|
-
# Copy node_modules from project root (npm installs there, not in .jac
|
|
166
|
+
# Copy node_modules from project root (npm installs there, not in .jac/client/configs)
|
|
166
167
|
source_node_modules = npm_cache_dir / "node_modules"
|
|
167
168
|
dest_node_modules = tmp_path / "node_modules"
|
|
168
169
|
if source_node_modules.exists():
|
|
@@ -195,10 +196,11 @@ antd = "^6.0.0"
|
|
|
195
196
|
jac_toml = tmp_path / "jac.toml"
|
|
196
197
|
jac_toml.write_text(jac_toml_content)
|
|
197
198
|
|
|
198
|
-
# Copy base .jac
|
|
199
|
-
source_configs = npm_cache_dir / ".jac
|
|
200
|
-
dest_configs = tmp_path / ".jac
|
|
199
|
+
# Copy base .jac/client/configs first for faster install
|
|
200
|
+
source_configs = npm_cache_dir / ".jac" / "client" / "configs"
|
|
201
|
+
dest_configs = tmp_path / ".jac" / "client" / "configs"
|
|
201
202
|
if source_configs.exists():
|
|
203
|
+
dest_configs.parent.mkdir(parents=True, exist_ok=True)
|
|
202
204
|
shutil.copytree(source_configs, dest_configs, symlinks=True)
|
|
203
205
|
|
|
204
206
|
# Copy base node_modules for faster install (npm will add antd on top)
|
|
@@ -32,51 +32,48 @@ walker positional_walker {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
# Client-side code testing both spawn orderings
|
|
35
|
-
cl import from react {
|
|
36
|
-
useState,
|
|
37
|
-
useEffect
|
|
38
|
-
}
|
|
35
|
+
cl import from react { useEffect }
|
|
39
36
|
|
|
40
37
|
cl {
|
|
41
38
|
def app() -> any {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
has standardResult: any = None;
|
|
40
|
+
has standardComputed: any = None;
|
|
41
|
+
has reverseResult: any = None;
|
|
42
|
+
has uuidResult: any = None;
|
|
43
|
+
has reverseUuidResult: any = None;
|
|
44
|
+
has positionalResult: any = None;
|
|
45
|
+
has spreadResult: any = None;
|
|
49
46
|
|
|
50
47
|
async def loadData() -> None {
|
|
51
48
|
# Test standard spawn order: node spawn walker()
|
|
52
49
|
data1 = root spawn test_walker();
|
|
53
|
-
|
|
50
|
+
standardResult = data1;
|
|
54
51
|
|
|
55
52
|
data2 = root spawn parameterized_walker(value=42);
|
|
56
|
-
|
|
53
|
+
standardComputed = data2;
|
|
57
54
|
|
|
58
55
|
# Test reverse spawn order: walker() spawn node
|
|
59
56
|
data3 = test_walker(message="Reverse spawn!") spawn root;
|
|
60
|
-
|
|
57
|
+
reverseResult = data3;
|
|
61
58
|
|
|
62
59
|
# Test spawn with UUID string: uuid_string spawn walker()
|
|
63
60
|
node_id = "550e8400-e29b-41d4-a716-446655440000";
|
|
64
61
|
data4 = node_id spawn test_walker();
|
|
65
|
-
|
|
62
|
+
uuidResult = data4;
|
|
66
63
|
|
|
67
64
|
# Test reverse spawn with UUID string: walker() spawn uuid_string
|
|
68
65
|
another_node_id = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
|
|
69
66
|
data5 = parameterized_walker(value=100) spawn another_node_id;
|
|
70
|
-
|
|
67
|
+
reverseUuidResult = data5;
|
|
71
68
|
|
|
72
69
|
# Test positional walker arguments inferred from has fields
|
|
73
70
|
data6 = node_id spawn positional_walker("Node positional", 2);
|
|
74
|
-
|
|
71
|
+
positionalResult = data6;
|
|
75
72
|
|
|
76
73
|
# Test **kwargs via spread when walker is on left-hand side
|
|
77
74
|
extra_fields = {"metadata": {"source": "client-side"}};
|
|
78
75
|
data7 = positional_walker("Spread order", 5, **extra_fields) spawn root;
|
|
79
|
-
|
|
76
|
+
spreadResult = data7;
|
|
80
77
|
}
|
|
81
78
|
|
|
82
79
|
useEffect(lambda -> None{ loadData();} , []);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
|
|
2
2
|
# Pages
|
|
3
|
-
cl import from react {
|
|
3
|
+
cl import from react { useEffect }
|
|
4
4
|
cl import from ".components/Button.tsx" { Button }
|
|
5
5
|
|
|
6
6
|
cl {
|
|
7
7
|
def app() -> any {
|
|
8
|
-
|
|
8
|
+
has count: int = 0;
|
|
9
9
|
useEffect(lambda -> None{ console.log("Count: ", count);} , [count]);
|
|
10
10
|
return <div
|
|
11
11
|
style={{padding: "2rem", fontFamily: "Arial, sans-serif"}}
|
|
@@ -21,12 +21,12 @@ cl {
|
|
|
21
21
|
>
|
|
22
22
|
<Button
|
|
23
23
|
label="Increment"
|
|
24
|
-
onClick={lambda -> None{
|
|
24
|
+
onClick={lambda -> None{ count = count + 1;} }
|
|
25
25
|
variant="primary"
|
|
26
26
|
/>
|
|
27
27
|
<Button
|
|
28
28
|
label="Reset"
|
|
29
|
-
onClick={lambda -> None{
|
|
29
|
+
onClick={lambda -> None{ count = 0;} }
|
|
30
30
|
variant="secondary"
|
|
31
31
|
/>
|
|
32
32
|
</div>
|