tova 0.1.0
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/LICENSE +21 -0
- package/README.md +112 -0
- package/bin/tova.js +1530 -0
- package/package.json +38 -0
- package/src/analyzer/analyzer.js +2053 -0
- package/src/analyzer/scope.js +60 -0
- package/src/codegen/base-codegen.js +1351 -0
- package/src/codegen/client-codegen.js +876 -0
- package/src/codegen/codegen.js +148 -0
- package/src/codegen/server-codegen.js +2506 -0
- package/src/codegen/shared-codegen.js +29 -0
- package/src/diagnostics/formatter.js +139 -0
- package/src/formatter/formatter.js +559 -0
- package/src/index.js +6 -0
- package/src/lexer/lexer.js +886 -0
- package/src/lexer/tokens.js +214 -0
- package/src/lsp/server.js +738 -0
- package/src/parser/ast.js +1135 -0
- package/src/parser/parser.js +2803 -0
- package/src/runtime/db.js +106 -0
- package/src/runtime/embedded.js +8 -0
- package/src/runtime/reactivity.js +1366 -0
- package/src/runtime/router.js +200 -0
- package/src/runtime/rpc.js +46 -0
- package/src/runtime/ssr.js +134 -0
- package/src/runtime/string-proto.js +27 -0
- package/src/stdlib/collections.js +90 -0
- package/src/stdlib/core.js +98 -0
- package/src/stdlib/inline.js +172 -0
- package/src/stdlib/string.js +100 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// Main code generator — orchestrates shared/server/client codegen
|
|
2
|
+
// Supports named multi-blocks: server "api" { }, server "ws" { }
|
|
3
|
+
// Blocks with the same name are merged; different names produce separate output files.
|
|
4
|
+
|
|
5
|
+
import { SharedCodegen } from './shared-codegen.js';
|
|
6
|
+
import { ServerCodegen } from './server-codegen.js';
|
|
7
|
+
import { ClientCodegen } from './client-codegen.js';
|
|
8
|
+
|
|
9
|
+
export class CodeGenerator {
|
|
10
|
+
constructor(ast, filename = '<stdin>') {
|
|
11
|
+
this.ast = ast;
|
|
12
|
+
this.filename = filename;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Group blocks by name (null name = "default")
|
|
16
|
+
_groupByName(blocks) {
|
|
17
|
+
const groups = new Map();
|
|
18
|
+
for (const block of blocks) {
|
|
19
|
+
const key = block.name || null;
|
|
20
|
+
if (!groups.has(key)) groups.set(key, []);
|
|
21
|
+
groups.get(key).push(block);
|
|
22
|
+
}
|
|
23
|
+
return groups;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
generate() {
|
|
27
|
+
const sharedBlocks = [];
|
|
28
|
+
const serverBlocks = [];
|
|
29
|
+
const clientBlocks = [];
|
|
30
|
+
const topLevel = [];
|
|
31
|
+
|
|
32
|
+
const testBlocks = [];
|
|
33
|
+
|
|
34
|
+
for (const node of this.ast.body) {
|
|
35
|
+
switch (node.type) {
|
|
36
|
+
case 'SharedBlock': sharedBlocks.push(node); break;
|
|
37
|
+
case 'ServerBlock': serverBlocks.push(node); break;
|
|
38
|
+
case 'ClientBlock': clientBlocks.push(node); break;
|
|
39
|
+
case 'TestBlock': testBlocks.push(node); break;
|
|
40
|
+
default: topLevel.push(node); break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const sharedGen = new SharedCodegen();
|
|
45
|
+
|
|
46
|
+
// All shared blocks (regardless of name) are merged into one shared output
|
|
47
|
+
const sharedCode = sharedBlocks.map(b => sharedGen.generate(b)).join('\n');
|
|
48
|
+
const topLevelCode = topLevel.map(s => sharedGen.generateStatement(s)).join('\n');
|
|
49
|
+
const helpers = sharedGen.generateHelpers();
|
|
50
|
+
const combinedShared = [helpers, sharedCode, topLevelCode].filter(s => s.trim()).join('\n').trim();
|
|
51
|
+
|
|
52
|
+
// Group server and client blocks by name
|
|
53
|
+
const serverGroups = this._groupByName(serverBlocks);
|
|
54
|
+
const clientGroups = this._groupByName(clientBlocks);
|
|
55
|
+
|
|
56
|
+
// Collect function names per named server block for inter-server RPC
|
|
57
|
+
const serverFunctionMap = new Map(); // blockName -> [fnName, ...]
|
|
58
|
+
const collectFns = (stmts) => {
|
|
59
|
+
const fns = [];
|
|
60
|
+
for (const stmt of stmts) {
|
|
61
|
+
if (stmt.type === 'FunctionDeclaration') {
|
|
62
|
+
fns.push(stmt.name);
|
|
63
|
+
} else if (stmt.type === 'RouteGroupDeclaration') {
|
|
64
|
+
fns.push(...collectFns(stmt.body));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return fns;
|
|
68
|
+
};
|
|
69
|
+
for (const [name, blocks] of serverGroups) {
|
|
70
|
+
if (name) {
|
|
71
|
+
const fns = [];
|
|
72
|
+
for (const block of blocks) {
|
|
73
|
+
fns.push(...collectFns(block.body));
|
|
74
|
+
}
|
|
75
|
+
serverFunctionMap.set(name, fns);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Generate server outputs (one per named group)
|
|
80
|
+
const servers = {};
|
|
81
|
+
for (const [name, blocks] of serverGroups) {
|
|
82
|
+
const gen = new ServerCodegen();
|
|
83
|
+
const key = name || 'default';
|
|
84
|
+
// Build peer blocks map (all named blocks except self)
|
|
85
|
+
let peerBlocks = null;
|
|
86
|
+
if (name && serverFunctionMap.size > 1) {
|
|
87
|
+
peerBlocks = new Map();
|
|
88
|
+
for (const [peerName, peerFns] of serverFunctionMap) {
|
|
89
|
+
if (peerName !== name) {
|
|
90
|
+
peerBlocks.set(peerName, peerFns);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
servers[key] = gen.generate(blocks, combinedShared, name, peerBlocks, sharedBlocks);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Generate client outputs (one per named group)
|
|
98
|
+
const clients = {};
|
|
99
|
+
for (const [name, blocks] of clientGroups) {
|
|
100
|
+
const gen = new ClientCodegen();
|
|
101
|
+
const key = name || 'default';
|
|
102
|
+
clients[key] = gen.generate(blocks, combinedShared);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Generate tests if test blocks exist
|
|
106
|
+
let testCode = '';
|
|
107
|
+
if (testBlocks.length > 0) {
|
|
108
|
+
const testGen = new ServerCodegen();
|
|
109
|
+
testCode = testGen.generateTests(testBlocks);
|
|
110
|
+
|
|
111
|
+
// Add __handleRequest export to server code
|
|
112
|
+
const defaultServer = servers['default'] || '';
|
|
113
|
+
if (defaultServer) {
|
|
114
|
+
servers['default'] = defaultServer + '\nexport { __handleRequest };\n';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Backward-compatible: if only unnamed blocks, return flat structure
|
|
119
|
+
const hasNamedBlocks = [...serverGroups.keys(), ...clientGroups.keys()].some(k => k !== null);
|
|
120
|
+
|
|
121
|
+
// Collect source mappings from all codegens
|
|
122
|
+
const sourceMappings = sharedGen.getSourceMappings();
|
|
123
|
+
|
|
124
|
+
if (!hasNamedBlocks) {
|
|
125
|
+
const result = {
|
|
126
|
+
shared: combinedShared,
|
|
127
|
+
server: servers['default'] || '',
|
|
128
|
+
client: clients['default'] || '',
|
|
129
|
+
sourceMappings,
|
|
130
|
+
};
|
|
131
|
+
if (testCode) result.test = testCode;
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Multi-block output: separate files per named block
|
|
136
|
+
const result = {
|
|
137
|
+
shared: combinedShared,
|
|
138
|
+
server: servers['default'] || '',
|
|
139
|
+
client: clients['default'] || '',
|
|
140
|
+
servers, // { "api": code, "ws": code, ... }
|
|
141
|
+
clients, // { "admin": code, "dashboard": code, ... }
|
|
142
|
+
multiBlock: true,
|
|
143
|
+
sourceMappings,
|
|
144
|
+
};
|
|
145
|
+
if (testCode) result.test = testCode;
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
}
|