tova 0.3.3 → 0.3.4

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.
package/bin/tova.js CHANGED
@@ -345,10 +345,8 @@ async function runTests(args) {
345
345
  const outDir = dirname(outPath);
346
346
  if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true });
347
347
 
348
- // Include stdlib + shared code + test code
349
- const stdlib = getFullStdlib();
350
- const fullTest = result.test;
351
- writeFileSync(outPath, fullTest);
348
+ // Shared code (top-level definitions) is now included by generateTests()
349
+ writeFileSync(outPath, result.test);
352
350
  compiledFiles.push(outPath);
353
351
  console.log(` Compiled: ${relative('.', file)}`);
354
352
  }
@@ -883,9 +881,16 @@ async function checkProject(args) {
883
881
  }
884
882
 
885
883
  const explicitSrc = args.filter(a => !a.startsWith('--'))[0];
886
- const srcDir = resolve(explicitSrc || '.');
884
+ const srcPath = resolve(explicitSrc || '.');
887
885
 
888
- const tovaFiles = findFiles(srcDir, '.tova');
886
+ // Support both single file and directory arguments
887
+ let tovaFiles;
888
+ if (existsSync(srcPath) && statSync(srcPath).isFile()) {
889
+ tovaFiles = srcPath.endsWith('.tova') ? [srcPath] : [];
890
+ } else {
891
+ tovaFiles = findFiles(srcPath, '.tova');
892
+ }
893
+ const srcDir = existsSync(srcPath) && statSync(srcPath).isFile() ? dirname(srcPath) : srcPath;
889
894
  if (tovaFiles.length === 0) {
890
895
  console.error('No .tova files found');
891
896
  process.exit(1);
@@ -2780,6 +2785,16 @@ async function productionBuild(srcDir, outDir) {
2780
2785
  console.log(` server.${hash}.js`);
2781
2786
  }
2782
2787
 
2788
+ // Write script bundle for plain scripts (no server/client blocks)
2789
+ if (!allServerCode.trim() && !allClientCode.trim() && allSharedCode.trim()) {
2790
+ const stdlib = getRunStdlib();
2791
+ const scriptBundle = stdlib + '\n' + allSharedCode;
2792
+ const hash = hashCode(scriptBundle);
2793
+ const scriptPath = join(outDir, `script.${hash}.js`);
2794
+ writeFileSync(scriptPath, scriptBundle);
2795
+ console.log(` script.${hash}.js`);
2796
+ }
2797
+
2783
2798
  // Write client bundle
2784
2799
  if (allClientCode.trim()) {
2785
2800
  const fullClientModule = allSharedCode + '\n' + allClientCode;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tova",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "Tova — a modern programming language that transpiles to JavaScript, unifying frontend and backend",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -160,7 +160,7 @@ export class CodeGenerator {
160
160
  let testCode = '';
161
161
  if (testBlocks.length > 0) {
162
162
  const testGen = new (getServerCodegen())();
163
- testCode = testGen.generateTests(testBlocks);
163
+ testCode = testGen.generateTests(testBlocks, combinedShared);
164
164
 
165
165
  // Add __handleRequest export to server code
166
166
  const defaultServer = servers['default'] || '';
@@ -173,7 +173,7 @@ export class CodeGenerator {
173
173
  let benchCode = '';
174
174
  if (benchBlocks.length > 0) {
175
175
  const benchGen = new (getServerCodegen())();
176
- benchCode = benchGen.generateBench(benchBlocks);
176
+ benchCode = benchGen.generateBench(benchBlocks, combinedShared);
177
177
  }
178
178
 
179
179
  // Backward-compatible: if only unnamed blocks, return flat structure
@@ -2677,7 +2677,7 @@ export class ServerCodegen extends BaseCodegen {
2677
2677
  this._emitHandlerCall(lines, `__grpChain(req)`, timeoutMs);
2678
2678
  }
2679
2679
 
2680
- generateTests(testBlocks) {
2680
+ generateTests(testBlocks, sharedCode) {
2681
2681
  const lines = [];
2682
2682
  lines.push('import { describe, test, expect } from "bun:test";');
2683
2683
  lines.push('');
@@ -2701,6 +2701,12 @@ export class ServerCodegen extends BaseCodegen {
2701
2701
  lines.push(' if (!condition) throw new Error(message || "Assertion failed");');
2702
2702
  lines.push('}');
2703
2703
  lines.push('');
2704
+ // Include top-level definitions (functions, variables) so tests can reference them
2705
+ if (sharedCode && sharedCode.trim()) {
2706
+ lines.push('// ── Module Code ──');
2707
+ lines.push(sharedCode);
2708
+ lines.push('');
2709
+ }
2704
2710
 
2705
2711
  for (const block of testBlocks) {
2706
2712
  const name = block.name || 'Tests';
@@ -2729,24 +2735,37 @@ export class ServerCodegen extends BaseCodegen {
2729
2735
  lines.push(' });');
2730
2736
  }
2731
2737
 
2732
- for (const stmt of block.body) {
2733
- if (stmt.type === 'FunctionDeclaration') {
2734
- const fnName = stmt.name;
2735
- const displayName = fnName.replace(/_/g, ' ');
2736
- this.pushScope();
2737
- for (const p of (stmt.params || [])) {
2738
- const pName = typeof p === 'string' ? p : (p.name || p.identifier);
2739
- if (pName) this.declareVar(pName);
2738
+ const hasFnTests = block.body.some(s => s.type === 'FunctionDeclaration');
2739
+
2740
+ if (hasFnTests) {
2741
+ // Function declarations become individual test cases
2742
+ for (const stmt of block.body) {
2743
+ if (stmt.type === 'FunctionDeclaration') {
2744
+ const fnName = stmt.name;
2745
+ const displayName = fnName.replace(/_/g, ' ');
2746
+ this.pushScope();
2747
+ for (const p of (stmt.params || [])) {
2748
+ const pName = typeof p === 'string' ? p : (p.name || p.identifier);
2749
+ if (pName) this.declareVar(pName);
2750
+ }
2751
+ const body = this.genBlockBody(stmt.body);
2752
+ this.popScope();
2753
+ const timeoutArg = blockTimeout ? `, ${blockTimeout}` : '';
2754
+ lines.push(` test(${JSON.stringify(displayName)}, async () => {`);
2755
+ lines.push(body);
2756
+ lines.push(` }${timeoutArg});`);
2757
+ } else {
2758
+ lines.push(' ' + this.generateStatement(stmt));
2740
2759
  }
2741
- const body = this.genBlockBody(stmt.body);
2742
- this.popScope();
2743
- const timeoutArg = blockTimeout ? `, ${blockTimeout}` : '';
2744
- lines.push(` test(${JSON.stringify(displayName)}, async () => {`);
2745
- lines.push(body);
2746
- lines.push(` }${timeoutArg});`);
2747
- } else {
2748
- lines.push(' ' + this.generateStatement(stmt));
2749
2760
  }
2761
+ } else {
2762
+ // No function declarations — wrap all statements in a single test case
2763
+ const timeoutArg = blockTimeout ? `, ${blockTimeout}` : '';
2764
+ lines.push(` test(${JSON.stringify(name)}, async () => {`);
2765
+ for (const stmt of block.body) {
2766
+ lines.push(' ' + this.generateStatement(stmt));
2767
+ }
2768
+ lines.push(` }${timeoutArg});`);
2750
2769
  }
2751
2770
  lines.push('});');
2752
2771
  lines.push('');
@@ -2755,10 +2774,16 @@ export class ServerCodegen extends BaseCodegen {
2755
2774
  return lines.join('\n');
2756
2775
  }
2757
2776
 
2758
- generateBench(benchBlocks) {
2777
+ generateBench(benchBlocks, sharedCode) {
2759
2778
  const lines = [];
2760
2779
  lines.push('// ── Tova Benchmark Runner ──');
2761
2780
  lines.push('');
2781
+ // Include top-level definitions (functions, variables) so benchmarks can reference them
2782
+ if (sharedCode && sharedCode.trim()) {
2783
+ lines.push('// ── Module Code ──');
2784
+ lines.push(sharedCode);
2785
+ lines.push('');
2786
+ }
2762
2787
  lines.push('async function __runBench(name, fn, runs) {');
2763
2788
  lines.push(' runs = runs || 100;');
2764
2789
  lines.push(' // Warmup');
package/src/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by scripts/embed-runtime.js — do not edit
2
- export const VERSION = "0.3.3";
2
+ export const VERSION = "0.3.4";