tova 0.4.0 → 0.4.1

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
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
3
  import { resolve, basename, dirname, join, relative } from 'path';
4
- import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSync, copyFileSync, rmSync, watch as fsWatch } from 'fs';
4
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSync, copyFileSync, rmSync, chmodSync, renameSync, watch as fsWatch } from 'fs';
5
5
  import { spawn } from 'child_process';
6
6
  // Bun.hash used instead of crypto.createHash for faster hashing
7
7
  import { Lexer } from '../src/lexer/lexer.js';
@@ -4397,6 +4397,17 @@ function detectInstallMethod() {
4397
4397
  return 'npm';
4398
4398
  }
4399
4399
 
4400
+ function compareSemver(a, b) {
4401
+ // Returns: -1 if a < b, 0 if a === b, 1 if a > b
4402
+ const pa = a.split('.').map(Number);
4403
+ const pb = b.split('.').map(Number);
4404
+ for (let i = 0; i < 3; i++) {
4405
+ if ((pa[i] || 0) < (pb[i] || 0)) return -1;
4406
+ if ((pa[i] || 0) > (pb[i] || 0)) return 1;
4407
+ }
4408
+ return 0;
4409
+ }
4410
+
4400
4411
  async function upgradeCommand() {
4401
4412
  console.log(`\n Current version: ${color.bold('Tova v' + VERSION)}\n`);
4402
4413
  console.log(' Checking for updates...');
@@ -4404,102 +4415,95 @@ async function upgradeCommand() {
4404
4415
  const installMethod = detectInstallMethod();
4405
4416
 
4406
4417
  try {
4418
+ // Always check npm registry as the source of truth for latest version
4419
+ const res = await fetch('https://registry.npmjs.org/tova/latest');
4420
+ if (!res.ok) {
4421
+ console.error(color.red(' Could not reach the npm registry. Check your network connection.'));
4422
+ process.exit(1);
4423
+ }
4424
+ const data = await res.json();
4425
+ const latestVersion = data.version;
4426
+
4427
+ if (compareSemver(VERSION, latestVersion) >= 0) {
4428
+ console.log(` ${color.green('Already on the latest version')} (v${VERSION}).\n`);
4429
+ return;
4430
+ }
4431
+
4432
+ console.log(` New version available: ${color.green('v' + latestVersion)}\n`);
4433
+
4407
4434
  if (installMethod === 'binary') {
4408
- // Binary install: check GitHub releases
4409
- const res = await fetch('https://api.github.com/repos/tova-lang/tova-lang/releases/latest');
4410
- if (!res.ok) {
4411
- console.error(color.red(' Could not reach GitHub. Check your network connection.'));
4412
- process.exit(1);
4435
+ console.log(' Upgrading via binary...');
4436
+
4437
+ // Check GitHub releases for the matching binary
4438
+ const ghRes = await fetch('https://api.github.com/repos/tova-lang/tova-lang/releases/latest');
4439
+ let ghTag = null;
4440
+ if (ghRes.ok) {
4441
+ const ghData = await ghRes.json();
4442
+ const ghVersion = (ghData.tag_name || '').replace(/^v/, '');
4443
+ if (compareSemver(ghVersion, VERSION) > 0) {
4444
+ ghTag = ghData.tag_name;
4445
+ }
4413
4446
  }
4414
- const data = await res.json();
4415
- const latestVersion = (data.tag_name || '').replace(/^v/, '');
4416
4447
 
4417
- if (latestVersion === VERSION) {
4418
- console.log(` ${color.green('Already on the latest version')} (v${VERSION}).\n`);
4448
+ if (!ghTag) {
4449
+ // No newer binary release available — fall back to npm install
4450
+ console.log(` ${color.dim('No binary release for v' + latestVersion + ' yet. Falling back to npm...')}\n`);
4451
+ await npmUpgrade(latestVersion);
4419
4452
  return;
4420
4453
  }
4421
4454
 
4422
- console.log(` New version available: ${color.green('v' + latestVersion)}\n`);
4423
- console.log(' Upgrading via binary...');
4424
-
4425
4455
  // Detect platform
4426
4456
  const platform = process.platform === 'darwin' ? 'darwin' : process.platform === 'linux' ? 'linux' : 'windows';
4427
4457
  const arch = process.arch === 'arm64' ? 'arm64' : 'x64';
4428
4458
  const assetName = `tova-${platform}-${arch}`;
4429
- const downloadUrl = `https://github.com/tova-lang/tova-lang/releases/download/${data.tag_name}/${assetName}.gz`;
4459
+ const downloadUrl = `https://github.com/tova-lang/tova-lang/releases/download/${ghTag}/${assetName}.gz`;
4430
4460
 
4431
4461
  const installDir = join(process.env.HOME || '', '.tova', 'bin');
4432
4462
  const tmpPath = join(installDir, 'tova.download');
4433
4463
  const binPath = join(installDir, 'tova');
4434
4464
 
4465
+ // Ensure install directory exists
4466
+ mkdirSync(installDir, { recursive: true });
4467
+
4435
4468
  // Download compressed binary
4436
4469
  const dlRes = await fetch(downloadUrl);
4437
4470
  if (!dlRes.ok) {
4438
4471
  // Fall back to uncompressed
4439
4472
  const dlRes2 = await fetch(downloadUrl.replace('.gz', ''));
4440
4473
  if (!dlRes2.ok) {
4441
- console.error(color.red(` Download failed. URL: ${downloadUrl.replace('.gz', '')}`));
4442
- process.exit(1);
4474
+ console.log(` ${color.dim('Binary download failed. Falling back to npm...')}\n`);
4475
+ await npmUpgrade(latestVersion);
4476
+ return;
4443
4477
  }
4444
4478
  writeFileSync(tmpPath, new Uint8Array(await dlRes2.arrayBuffer()));
4445
4479
  } else {
4446
4480
  // Decompress gzip
4447
4481
  const compressed = new Uint8Array(await dlRes.arrayBuffer());
4448
- const decompressed = Bun.gunzipSync(compressed);
4482
+ const { gunzipSync } = await import('zlib');
4483
+ const decompressed = gunzipSync(compressed);
4449
4484
  writeFileSync(tmpPath, decompressed);
4450
4485
  }
4451
4486
 
4452
4487
  // Make executable
4453
- const { chmodSync } = await import('fs');
4454
4488
  chmodSync(tmpPath, 0o755);
4455
4489
 
4456
4490
  // Verify the new binary works
4457
- const verifyProc = Bun.spawnSync([tmpPath, '--version'], { stdout: 'pipe', stderr: 'pipe' });
4458
- if (verifyProc.exitCode !== 0) {
4491
+ const { spawnSync } = await import('child_process');
4492
+ const verifyProc = spawnSync(tmpPath, ['--version'], { timeout: 10000 });
4493
+ if (verifyProc.status !== 0) {
4459
4494
  rmSync(tmpPath, { force: true });
4460
- console.error(color.red(' Downloaded binary verification failed.'));
4461
- process.exit(1);
4495
+ console.error(color.red(' Downloaded binary verification failed. Falling back to npm...'));
4496
+ await npmUpgrade(latestVersion);
4497
+ return;
4462
4498
  }
4463
4499
 
4464
4500
  // Atomic rename
4465
- const { renameSync } = await import('fs');
4466
4501
  renameSync(tmpPath, binPath);
4467
4502
 
4468
4503
  console.log(`\n ${color.green('✓')} Upgraded: v${VERSION} -> ${color.bold('v' + latestVersion)}\n`);
4469
4504
  } else {
4470
- // npm/bun install: check npm registry
4471
- const res = await fetch('https://registry.npmjs.org/tova/latest');
4472
- if (!res.ok) {
4473
- console.error(color.red(' Could not reach the npm registry. Check your network connection.'));
4474
- process.exit(1);
4475
- }
4476
- const data = await res.json();
4477
- const latestVersion = data.version;
4478
-
4479
- if (latestVersion === VERSION) {
4480
- console.log(` ${color.green('Already on the latest version')} (v${VERSION}).\n`);
4481
- return;
4482
- }
4483
-
4484
- console.log(` New version available: ${color.green('v' + latestVersion)}\n`);
4485
4505
  console.log(' Upgrading...');
4486
-
4487
- const pm = detectPackageManager();
4488
- const installCmd = pm === 'bun' ? ['bun', ['add', '-g', 'tova@latest']]
4489
- : pm === 'pnpm' ? ['pnpm', ['add', '-g', 'tova@latest']]
4490
- : pm === 'yarn' ? ['yarn', ['global', 'add', 'tova@latest']]
4491
- : ['npm', ['install', '-g', 'tova@latest']];
4492
-
4493
- const proc = spawn(installCmd[0], installCmd[1], { stdio: 'inherit' });
4494
- const exitCode = await new Promise(res => proc.on('close', res));
4495
-
4496
- if (exitCode === 0) {
4497
- console.log(`\n ${color.green('✓')} Upgraded to Tova v${latestVersion}.\n`);
4498
- } else {
4499
- console.error(color.red(`\n Upgrade failed (exit code ${exitCode}).`));
4500
- console.error(` Try manually: ${installCmd[0]} ${installCmd[1].join(' ')}\n`);
4501
- process.exit(1);
4502
- }
4506
+ await npmUpgrade(latestVersion);
4503
4507
  }
4504
4508
  } catch (err) {
4505
4509
  console.error(color.red(` Upgrade failed: ${err.message}`));
@@ -4512,6 +4516,25 @@ async function upgradeCommand() {
4512
4516
  }
4513
4517
  }
4514
4518
 
4519
+ async function npmUpgrade(latestVersion) {
4520
+ const pm = detectPackageManager();
4521
+ const installCmd = pm === 'bun' ? ['bun', ['add', '-g', 'tova@latest']]
4522
+ : pm === 'pnpm' ? ['pnpm', ['add', '-g', 'tova@latest']]
4523
+ : pm === 'yarn' ? ['yarn', ['global', 'add', 'tova@latest']]
4524
+ : ['npm', ['install', '-g', 'tova@latest']];
4525
+
4526
+ const proc = spawn(installCmd[0], installCmd[1], { stdio: 'inherit' });
4527
+ const exitCode = await new Promise(res => proc.on('close', res));
4528
+
4529
+ if (exitCode === 0) {
4530
+ console.log(`\n ${color.green('✓')} Upgraded to Tova v${latestVersion}.\n`);
4531
+ } else {
4532
+ console.error(color.red(`\n Upgrade failed (exit code ${exitCode}).`));
4533
+ console.error(` Try manually: ${installCmd[0]} ${installCmd[1].join(' ')}\n`);
4534
+ process.exit(1);
4535
+ }
4536
+ }
4537
+
4515
4538
  function detectPackageManager() {
4516
4539
  if (typeof Bun !== 'undefined') return 'bun';
4517
4540
  const ua = process.env.npm_config_user_agent || '';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tova",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
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",
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.4.0";
2
+ export const VERSION = "0.4.1";