tova 0.9.10 → 0.9.11
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 +11 -8
- package/package.json +1 -1
- package/src/codegen/codegen.js +2 -0
- package/src/codegen/server-codegen.js +38 -2
- package/src/version.js +1 -1
package/bin/tova.js
CHANGED
|
@@ -1568,7 +1568,7 @@ async function devServer(args) {
|
|
|
1568
1568
|
for (const [dir, files] of dirGroups) {
|
|
1569
1569
|
const dirName = basename(dir) === '.' ? 'app' : basename(dir);
|
|
1570
1570
|
try {
|
|
1571
|
-
const result = mergeDirectory(dir, srcDir, { strict: buildStrict, strictSecurity: buildStrictSecurity });
|
|
1571
|
+
const result = mergeDirectory(dir, srcDir, { strict: buildStrict, strictSecurity: buildStrictSecurity, isDev: true });
|
|
1572
1572
|
if (!result) continue;
|
|
1573
1573
|
|
|
1574
1574
|
const { output, single } = result;
|
|
@@ -1663,7 +1663,7 @@ async function devServer(args) {
|
|
|
1663
1663
|
|
|
1664
1664
|
const child = spawn('bun', ['run', sf.path], {
|
|
1665
1665
|
stdio: 'inherit',
|
|
1666
|
-
env: { ...process.env, [envKey]: String(port), PORT: String(port) },
|
|
1666
|
+
env: { ...process.env, [envKey]: String(port), PORT: String(port), __TOVA_HMR_STATE_PATH: join(outDir, '.hmr-state.json') },
|
|
1667
1667
|
});
|
|
1668
1668
|
|
|
1669
1669
|
child.on('error', (err) => {
|
|
@@ -1813,7 +1813,7 @@ async function devServer(args) {
|
|
|
1813
1813
|
|
|
1814
1814
|
for (const [dir, files] of rebuildDirGroups) {
|
|
1815
1815
|
const dirName = basename(dir) === '.' ? 'app' : basename(dir);
|
|
1816
|
-
const result = mergeDirectory(dir, srcDir, { strict: buildStrict, strictSecurity: buildStrictSecurity });
|
|
1816
|
+
const result = mergeDirectory(dir, srcDir, { strict: buildStrict, strictSecurity: buildStrictSecurity, isDev: true });
|
|
1817
1817
|
if (!result) continue;
|
|
1818
1818
|
|
|
1819
1819
|
const { output, single } = result;
|
|
@@ -1890,7 +1890,7 @@ async function devServer(args) {
|
|
|
1890
1890
|
const port = basePort + rebuildPortOffset;
|
|
1891
1891
|
const child = spawn('bun', ['run', serverPath], {
|
|
1892
1892
|
stdio: 'inherit',
|
|
1893
|
-
env: { ...process.env, PORT: String(port) },
|
|
1893
|
+
env: { ...process.env, PORT: String(port), __TOVA_HMR_STATE_PATH: join(outDir, '.hmr-state.json') },
|
|
1894
1894
|
});
|
|
1895
1895
|
processes.push({ child, label: 'server', port });
|
|
1896
1896
|
rebuildPortOffset++;
|
|
@@ -1921,6 +1921,9 @@ async function devServer(args) {
|
|
|
1921
1921
|
for (const p of processes) {
|
|
1922
1922
|
try { p.child.kill('SIGKILL'); } catch {}
|
|
1923
1923
|
}
|
|
1924
|
+
// Clean up HMR state file for fresh start next time
|
|
1925
|
+
const hmrPath = join(outDir, '.hmr-state.json');
|
|
1926
|
+
try { if (existsSync(hmrPath)) rmSync(hmrPath); } catch {}
|
|
1924
1927
|
process.exit(0);
|
|
1925
1928
|
});
|
|
1926
1929
|
|
|
@@ -5663,7 +5666,7 @@ function collectExports(ast, filename) {
|
|
|
5663
5666
|
return { publicExports, allNames };
|
|
5664
5667
|
}
|
|
5665
5668
|
|
|
5666
|
-
function compileWithImports(source, filename, srcDir) {
|
|
5669
|
+
function compileWithImports(source, filename, srcDir, options = {}) {
|
|
5667
5670
|
if (compilationCache.has(filename)) {
|
|
5668
5671
|
return compilationCache.get(filename);
|
|
5669
5672
|
}
|
|
@@ -5768,7 +5771,7 @@ function compileWithImports(source, filename, srcDir) {
|
|
|
5768
5771
|
}
|
|
5769
5772
|
}
|
|
5770
5773
|
|
|
5771
|
-
const codegen = new CodeGenerator(ast, filename);
|
|
5774
|
+
const codegen = new CodeGenerator(ast, filename, { isDev: options.isDev });
|
|
5772
5775
|
const output = codegen.generate();
|
|
5773
5776
|
compilationCache.set(filename, output);
|
|
5774
5777
|
return output;
|
|
@@ -5904,7 +5907,7 @@ function mergeDirectory(dir, srcDir, options = {}) {
|
|
|
5904
5907
|
// Single file — use existing per-file compilation
|
|
5905
5908
|
const file = tovaFiles[0];
|
|
5906
5909
|
const source = readFileSync(file, 'utf-8');
|
|
5907
|
-
return { output: compileWithImports(source, file, srcDir), files: [file], single: true };
|
|
5910
|
+
return { output: compileWithImports(source, file, srcDir, { isDev: options.isDev }), files: [file], single: true };
|
|
5908
5911
|
}
|
|
5909
5912
|
|
|
5910
5913
|
// Parse all files in the directory
|
|
@@ -6020,7 +6023,7 @@ function mergeDirectory(dir, srcDir, options = {}) {
|
|
|
6020
6023
|
}
|
|
6021
6024
|
|
|
6022
6025
|
// Run codegen on merged AST
|
|
6023
|
-
const codegen = new CodeGenerator(mergedAST, dir);
|
|
6026
|
+
const codegen = new CodeGenerator(mergedAST, dir, { isDev: options.isDev });
|
|
6024
6027
|
const output = codegen.generate();
|
|
6025
6028
|
|
|
6026
6029
|
// Collect source content from all files for source maps
|
package/package.json
CHANGED
package/src/codegen/codegen.js
CHANGED
|
@@ -59,6 +59,7 @@ export class CodeGenerator {
|
|
|
59
59
|
this.ast = ast;
|
|
60
60
|
this.filename = filename;
|
|
61
61
|
this._sourceMaps = options.sourceMaps !== false; // default true; pass false for REPL/check
|
|
62
|
+
this._isDev = options.isDev || false;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
// Group blocks by name (null name = "default")
|
|
@@ -250,6 +251,7 @@ export class CodeGenerator {
|
|
|
250
251
|
for (const [name, blocks] of serverGroups) {
|
|
251
252
|
const gen = new (getServerCodegen())();
|
|
252
253
|
gen._sourceMapsEnabled = this._sourceMaps;
|
|
254
|
+
gen._isDev = this._isDev;
|
|
253
255
|
const key = name || 'default';
|
|
254
256
|
// Build peer blocks map (all named blocks except self)
|
|
255
257
|
let peerBlocks = null;
|
|
@@ -240,6 +240,7 @@ export class ServerCodegen extends BaseCodegen {
|
|
|
240
240
|
const functions = [];
|
|
241
241
|
const middlewares = [];
|
|
242
242
|
const otherStatements = [];
|
|
243
|
+
const hmrVarNames = [];
|
|
243
244
|
let healthPath = null;
|
|
244
245
|
let healthChecks = null;
|
|
245
246
|
let corsConfig = null;
|
|
@@ -2142,8 +2143,29 @@ export class ServerCodegen extends BaseCodegen {
|
|
|
2142
2143
|
// ════════════════════════════════════════════════════════════
|
|
2143
2144
|
// 13. Other statements + Server Functions
|
|
2144
2145
|
// ════════════════════════════════════════════════════════════
|
|
2146
|
+
if (this._isDev) {
|
|
2147
|
+
lines.push('// ── HMR State ──');
|
|
2148
|
+
lines.push('const __hmrStatePath = process.env.__TOVA_HMR_STATE_PATH || "";');
|
|
2149
|
+
lines.push('let __hmrState = {};');
|
|
2150
|
+
lines.push('if (__hmrStatePath) { try { __hmrState = JSON.parse(require("fs").readFileSync(__hmrStatePath, "utf-8")); } catch {} }');
|
|
2151
|
+
lines.push('');
|
|
2152
|
+
}
|
|
2145
2153
|
for (const stmt of otherStatements) {
|
|
2146
|
-
|
|
2154
|
+
// HMR wrapping: new variable declarations get restored from __hmrState
|
|
2155
|
+
const isHmrEligible = this._isDev && stmt.targets && stmt.targets.length === 1 &&
|
|
2156
|
+
stmt.values && stmt.values.length === 1 && typeof stmt.targets[0] === 'string' &&
|
|
2157
|
+
(stmt.type === 'Assignment' ? !this.isDeclared(stmt.targets[0]) : stmt.type === 'VarDeclaration');
|
|
2158
|
+
if (isHmrEligible) {
|
|
2159
|
+
const name = stmt.targets[0];
|
|
2160
|
+
hmrVarNames.push(name);
|
|
2161
|
+
this.declareVar(name);
|
|
2162
|
+
if (stmt.isPublic) this._userDefinedNames.add(name);
|
|
2163
|
+
const initExpr = this.genExpression(stmt.values[0]);
|
|
2164
|
+
const keyword = stmt.type === 'VarDeclaration' ? 'let' : 'const';
|
|
2165
|
+
lines.push(`${keyword} ${name} = (${JSON.stringify(name)} in __hmrState) ? __hmrState[${JSON.stringify(name)}] : ${initExpr};`);
|
|
2166
|
+
} else {
|
|
2167
|
+
lines.push(this.generateStatement(stmt));
|
|
2168
|
+
}
|
|
2147
2169
|
}
|
|
2148
2170
|
|
|
2149
2171
|
if (functions.length > 0) {
|
|
@@ -3688,10 +3710,24 @@ export class ServerCodegen extends BaseCodegen {
|
|
|
3688
3710
|
// 24. Graceful Shutdown — on_stop hooks (F3) + clearInterval (F8)
|
|
3689
3711
|
// ════════════════════════════════════════════════════════════
|
|
3690
3712
|
lines.push('// ── Graceful Shutdown ──');
|
|
3713
|
+
// HMR state-save helper (emitted as first action in __shutdown)
|
|
3714
|
+
const hmrSaveLines = [];
|
|
3715
|
+
if (this._isDev && hmrVarNames.length > 0) {
|
|
3716
|
+
const entries = hmrVarNames.map(n => `${JSON.stringify(n)}: ${n}`).join(', ');
|
|
3717
|
+
hmrSaveLines.push(` try { require("fs").writeFileSync(__hmrStatePath, JSON.stringify({ ${entries} })); } catch {}`);
|
|
3718
|
+
}
|
|
3691
3719
|
if (isFastMode) {
|
|
3692
|
-
|
|
3720
|
+
if (hmrSaveLines.length > 0) {
|
|
3721
|
+
lines.push('function __shutdown() {');
|
|
3722
|
+
for (const l of hmrSaveLines) lines.push(l);
|
|
3723
|
+
lines.push(' __server.stop(); process.exit(0);');
|
|
3724
|
+
lines.push('}');
|
|
3725
|
+
} else {
|
|
3726
|
+
lines.push('function __shutdown() { __server.stop(); process.exit(0); }');
|
|
3727
|
+
}
|
|
3693
3728
|
} else {
|
|
3694
3729
|
lines.push('async function __shutdown() {');
|
|
3730
|
+
for (const l of hmrSaveLines) lines.push(l);
|
|
3695
3731
|
lines.push(` console.log(\`Tova server${label} shutting down...\`);`);
|
|
3696
3732
|
lines.push(' __shuttingDown = true;');
|
|
3697
3733
|
lines.push(' __server.stop();');
|
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.9.
|
|
2
|
+
export const VERSION = "0.9.11";
|