tova 0.7.0 → 0.9.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.
Files changed (59) hide show
  1. package/bin/tova.js +1312 -139
  2. package/package.json +8 -1
  3. package/src/analyzer/analyzer.js +539 -11
  4. package/src/analyzer/browser-analyzer.js +56 -8
  5. package/src/analyzer/deploy-analyzer.js +44 -0
  6. package/src/analyzer/scope.js +7 -0
  7. package/src/analyzer/server-analyzer.js +33 -1
  8. package/src/codegen/base-codegen.js +1296 -23
  9. package/src/codegen/browser-codegen.js +725 -20
  10. package/src/codegen/codegen.js +87 -5
  11. package/src/codegen/deploy-codegen.js +49 -0
  12. package/src/codegen/server-codegen.js +54 -6
  13. package/src/codegen/shared-codegen.js +5 -0
  14. package/src/codegen/theme-codegen.js +69 -0
  15. package/src/codegen/wasm-codegen.js +6 -0
  16. package/src/config/edit-toml.js +6 -2
  17. package/src/config/git-resolver.js +128 -0
  18. package/src/config/lock-file.js +57 -0
  19. package/src/config/module-cache.js +58 -0
  20. package/src/config/module-entry.js +37 -0
  21. package/src/config/module-path.js +63 -0
  22. package/src/config/pkg-errors.js +62 -0
  23. package/src/config/resolve.js +26 -0
  24. package/src/config/resolver.js +139 -0
  25. package/src/config/search.js +28 -0
  26. package/src/config/semver.js +72 -0
  27. package/src/config/toml.js +61 -6
  28. package/src/deploy/deploy.js +217 -0
  29. package/src/deploy/infer.js +218 -0
  30. package/src/deploy/provision.js +315 -0
  31. package/src/diagnostics/security-scorecard.js +111 -0
  32. package/src/lexer/lexer.js +18 -3
  33. package/src/lsp/server.js +482 -0
  34. package/src/parser/animate-ast.js +45 -0
  35. package/src/parser/ast.js +39 -0
  36. package/src/parser/browser-ast.js +19 -1
  37. package/src/parser/browser-parser.js +221 -4
  38. package/src/parser/concurrency-ast.js +15 -0
  39. package/src/parser/concurrency-parser.js +236 -0
  40. package/src/parser/deploy-ast.js +37 -0
  41. package/src/parser/deploy-parser.js +132 -0
  42. package/src/parser/parser.js +42 -5
  43. package/src/parser/select-ast.js +39 -0
  44. package/src/parser/theme-ast.js +29 -0
  45. package/src/parser/theme-parser.js +70 -0
  46. package/src/registry/plugins/concurrency-plugin.js +32 -0
  47. package/src/registry/plugins/deploy-plugin.js +33 -0
  48. package/src/registry/plugins/theme-plugin.js +20 -0
  49. package/src/registry/register-all.js +6 -0
  50. package/src/runtime/charts.js +547 -0
  51. package/src/runtime/embedded.js +6 -2
  52. package/src/runtime/reactivity.js +60 -0
  53. package/src/runtime/router.js +703 -295
  54. package/src/runtime/table.js +606 -33
  55. package/src/stdlib/inline.js +365 -10
  56. package/src/stdlib/runtime-bridge.js +152 -0
  57. package/src/stdlib/string.js +84 -2
  58. package/src/stdlib/validation.js +1 -1
  59. package/src/version.js +1 -1
@@ -0,0 +1,152 @@
1
+ // Tova Runtime Bridge
2
+ // Auto-discovers the native tova_runtime addon (napi-rs) and exposes a clean API.
3
+ // Falls back gracefully when the addon is not available.
4
+
5
+ 'use strict';
6
+
7
+ let _runtime = null; // null = not yet attempted, false = failed, object = loaded
8
+ let _available = false;
9
+
10
+ function _findAndLoad() {
11
+ const { existsSync, readdirSync } = require('fs');
12
+ const { join, dirname } = require('path');
13
+
14
+ const searchDirs = [
15
+ // Relative to this file (src/stdlib/) -> project root tova_runtime/
16
+ join(dirname(__filename), '..', '..', 'tova_runtime'),
17
+ join(dirname(__filename), '..', '..', 'tova_runtime', 'target', 'release'),
18
+ // System-wide install
19
+ join(process.env.HOME || '', '.tova', 'lib'),
20
+ // Next to the running script
21
+ dirname(process.argv[1] || ''),
22
+ ];
23
+
24
+ for (const dir of searchDirs) {
25
+ if (!existsSync(dir)) continue;
26
+
27
+ let entries;
28
+ try { entries = readdirSync(dir); } catch (_) { continue; }
29
+
30
+ // Search .node files first (napi-rs convention)
31
+ const nodeFiles = entries.filter(f => f.endsWith('.node'));
32
+ for (const f of nodeFiles) {
33
+ try { return require(join(dir, f)); } catch (_) { continue; }
34
+ }
35
+
36
+ // Fall back to .dylib files (macOS raw cargo output)
37
+ const dylibFiles = entries.filter(f => f.endsWith('.dylib') && f.startsWith('libtova_runtime'));
38
+ for (const f of dylibFiles) {
39
+ try { return require(join(dir, f)); } catch (_) { continue; }
40
+ }
41
+ }
42
+
43
+ return null;
44
+ }
45
+
46
+ function _init() {
47
+ if (_runtime !== null) return _available;
48
+
49
+ try {
50
+ const loaded = _findAndLoad();
51
+ if (loaded && typeof loaded.healthCheck === 'function') {
52
+ _runtime = loaded;
53
+ _available = true;
54
+ } else {
55
+ _runtime = false;
56
+ _available = false;
57
+ }
58
+ } catch (_) {
59
+ _runtime = false;
60
+ _available = false;
61
+ }
62
+
63
+ return _available;
64
+ }
65
+
66
+ // --- Public API ---
67
+
68
+ function isRuntimeAvailable() {
69
+ return _init();
70
+ }
71
+
72
+ function healthCheck() {
73
+ if (!_init()) return null;
74
+ return _runtime.healthCheck();
75
+ }
76
+
77
+ function channelCreate(capacity) {
78
+ if (!_init()) throw new Error('tova_runtime not available');
79
+ return _runtime.channelCreate(capacity);
80
+ }
81
+
82
+ function channelSend(id, value) {
83
+ if (!_init()) throw new Error('tova_runtime not available');
84
+ return _runtime.channelSend(id, value);
85
+ }
86
+
87
+ function channelReceive(id) {
88
+ if (!_init()) throw new Error('tova_runtime not available');
89
+ return _runtime.channelReceive(id);
90
+ }
91
+
92
+ function channelClose(id) {
93
+ if (!_init()) throw new Error('tova_runtime not available');
94
+ _runtime.channelClose(id);
95
+ }
96
+
97
+ function execWasm(bytes, func, args) {
98
+ if (!_init()) return Promise.reject(new Error('tova_runtime not available'));
99
+ return _runtime.execWasm(bytes, func, args);
100
+ }
101
+
102
+ function execWasmWithChannels(bytes, func, args) {
103
+ if (!_init()) return Promise.reject(new Error('tova_runtime not available'));
104
+ return _runtime.execWasmWithChannels(bytes, func, args);
105
+ }
106
+
107
+ function concurrentWasm(tasks) {
108
+ if (!_init()) return Promise.reject(new Error('tova_runtime not available'));
109
+ return _runtime.concurrentWasm(tasks);
110
+ }
111
+
112
+ function concurrentWasmWithChannels(tasks) {
113
+ if (!_init()) return Promise.reject(new Error('tova_runtime not available'));
114
+ return _runtime.concurrentWasmWithChannels(tasks);
115
+ }
116
+
117
+ function concurrentWasmShared(tasks) {
118
+ if (!_init()) return Promise.reject(new Error('tova_runtime not available'));
119
+ return _runtime.concurrentWasmShared(tasks);
120
+ }
121
+
122
+ function concurrentWasmFirst(tasks) {
123
+ if (!_init()) return Promise.reject(new Error('tova_runtime not available'));
124
+ return _runtime.concurrentWasmFirst(tasks);
125
+ }
126
+
127
+ function concurrentWasmTimeout(tasks, timeoutMs) {
128
+ if (!_init()) return Promise.reject(new Error('tova_runtime not available'));
129
+ return _runtime.concurrentWasmTimeout(tasks, timeoutMs);
130
+ }
131
+
132
+ function concurrentWasmCancelOnError(tasks) {
133
+ if (!_init()) return Promise.reject(new Error('tova_runtime not available'));
134
+ return _runtime.concurrentWasmCancelOnError(tasks);
135
+ }
136
+
137
+ module.exports = {
138
+ isRuntimeAvailable,
139
+ healthCheck,
140
+ channelCreate,
141
+ channelSend,
142
+ channelReceive,
143
+ channelClose,
144
+ execWasm,
145
+ execWasmWithChannels,
146
+ concurrentWasm,
147
+ concurrentWasmWithChannels,
148
+ concurrentWasmShared,
149
+ concurrentWasmFirst,
150
+ concurrentWasmTimeout,
151
+ concurrentWasmCancelOnError,
152
+ };
@@ -190,6 +190,88 @@ export function unescape_html(s) {
190
190
  }
191
191
 
192
192
  export function fmt(template, ...args) {
193
- let i = 0;
194
- return template.replace(/\{\}/g, () => i < args.length ? String(args[i++]) : '{}');
193
+ var named = args.length === 1 && args[0] !== null && typeof args[0] === 'object' && !Array.isArray(args[0]) && !(args[0] instanceof Date);
194
+ var obj = named ? args[0] : null;
195
+ var ai = 0, result = '', pos = 0, len = template.length;
196
+ while (pos < len) {
197
+ if (pos + 1 < len && template[pos] === '{' && template[pos + 1] === '{') { result += '{'; pos += 2; continue; }
198
+ if (pos + 1 < len && template[pos] === '}' && template[pos + 1] === '}') { result += '}'; pos += 2; continue; }
199
+ if (template[pos] === '{') {
200
+ var close = template.indexOf('}', pos + 1);
201
+ if (close === -1) { result += template[pos]; pos++; continue; }
202
+ var inner = template.substring(pos + 1, close);
203
+ pos = close + 1;
204
+ var colonIdx = inner.indexOf(':');
205
+ var key = colonIdx >= 0 ? inner.substring(0, colonIdx) : inner;
206
+ var spec = colonIdx >= 0 ? inner.substring(colonIdx + 1) : '';
207
+ var val;
208
+ if (named && key.length > 0) {
209
+ val = obj[key]; if (val === undefined) { result += '{' + inner + '}'; continue; }
210
+ } else if (key.length === 0) {
211
+ if (ai < args.length) { val = args[ai++]; } else { result += '{}'; continue; }
212
+ } else {
213
+ if (ai < args.length) { val = args[ai++]; } else { result += '{' + inner + '}'; continue; }
214
+ }
215
+ if (!spec) { result += String(val); continue; }
216
+ var si = 0, fill = ' ', align = '', sign = '', comma = false, width = 0, hasWidth = false, precision = -1, type = '';
217
+ if (si + 1 < spec.length && (spec[si + 1] === '<' || spec[si + 1] === '>' || spec[si + 1] === '^')) { fill = spec[si]; align = spec[si + 1]; si += 2; }
218
+ else if (si < spec.length && (spec[si] === '<' || spec[si] === '>' || spec[si] === '^')) { align = spec[si]; si += 1; }
219
+ if (si < spec.length && (spec[si] === '+' || spec[si] === '-' || spec[si] === ' ')) { sign = spec[si]; si += 1; }
220
+ while (si < spec.length && spec[si] >= '0' && spec[si] <= '9') { width = width * 10 + (spec.charCodeAt(si) - 48); hasWidth = true; si += 1; }
221
+ if (si < spec.length && spec[si] === ',') { comma = true; si += 1; }
222
+ if (si < spec.length && spec[si] === '.') { si += 1; precision = 0; while (si < spec.length && spec[si] >= '0' && spec[si] <= '9') { precision = precision * 10 + (spec.charCodeAt(si) - 48); si += 1; } }
223
+ if (si < spec.length) { type = spec[si]; }
224
+ var formatted, numVal = typeof val === 'number' ? val : Number(val);
225
+ switch (type) {
226
+ case 'b': formatted = (numVal >>> 0).toString(2); if (numVal === 0) formatted = '0'; break;
227
+ case 'o': formatted = (numVal >>> 0).toString(8); if (numVal === 0) formatted = '0'; break;
228
+ case 'x': formatted = (numVal >>> 0).toString(16); if (numVal === 0) formatted = '0'; break;
229
+ case 'X': formatted = (numVal >>> 0).toString(16).toUpperCase(); if (numVal === 0) formatted = '0'; break;
230
+ case 'f': formatted = numVal.toFixed(precision >= 0 ? precision : 6); break;
231
+ case '%': {
232
+ var pct = numVal * 100;
233
+ formatted = precision >= 0 ? pct.toFixed(precision) + '%' : (Math.round(pct * 1e10) / 1e10).toString() + '%';
234
+ break;
235
+ }
236
+ case '$': {
237
+ var abs = Math.abs(numVal), dollars = abs.toFixed(2), dotIdx2 = dollars.indexOf('.'), intPart2 = dollars.substring(0, dotIdx2), decPart2 = dollars.substring(dotIdx2);
238
+ var withCommas2 = '';
239
+ for (var j2 = 0; j2 < intPart2.length; j2++) { if (j2 > 0 && (intPart2.length - j2) % 3 === 0) withCommas2 += ','; withCommas2 += intPart2[j2]; }
240
+ formatted = (numVal < 0 ? '-' : '') + '$' + withCommas2 + decPart2;
241
+ break;
242
+ }
243
+ case 's': formatted = String(val); if (precision >= 0) formatted = formatted.substring(0, precision); break;
244
+ default:
245
+ if (typeof val === 'number' && precision >= 0 && !type) formatted = numVal.toFixed(precision);
246
+ else formatted = String(val);
247
+ break;
248
+ }
249
+ if (comma && type !== '$') {
250
+ var dIdx = formatted.indexOf('.'), iPart = dIdx >= 0 ? formatted.substring(0, dIdx) : formatted, dPart = dIdx >= 0 ? formatted.substring(dIdx) : '';
251
+ var signChar = '', digits = iPart;
252
+ if (digits[0] === '-' || digits[0] === '+') { signChar = digits[0]; digits = digits.substring(1); }
253
+ var withC = '';
254
+ for (var j = 0; j < digits.length; j++) { if (j > 0 && (digits.length - j) % 3 === 0) withC += ','; withC += digits[j]; }
255
+ formatted = signChar + withC + dPart;
256
+ }
257
+ if (sign && type !== '$' && type !== '%') {
258
+ if (typeof val === 'number') {
259
+ var s = formatted;
260
+ if (s[0] === '-' || s[0] === '+') { s = s.substring(1); }
261
+ if (numVal >= 0) { if (sign === '+') formatted = '+' + s; else if (sign === ' ') formatted = ' ' + s; else formatted = s; }
262
+ else { formatted = '-' + s; }
263
+ }
264
+ }
265
+ if (hasWidth && formatted.length < width) {
266
+ var pad = width - formatted.length, a = align || '>';
267
+ if (a === '<') formatted = formatted + fill.repeat(pad);
268
+ else if (a === '^') { var left = Math.floor(pad / 2); formatted = fill.repeat(left) + formatted + fill.repeat(pad - left); }
269
+ else formatted = fill.repeat(pad) + formatted;
270
+ }
271
+ result += formatted;
272
+ continue;
273
+ }
274
+ result += template[pos]; pos++;
275
+ }
276
+ return result;
195
277
  }
@@ -9,7 +9,7 @@ export function is_url(s) {
9
9
  }
10
10
 
11
11
  export function is_numeric(s) {
12
- return typeof s === 'string' && s.length > 0 && !isNaN(Number(s));
12
+ return typeof s === 'string' && s.length > 0 && s.trim().length > 0 && !isNaN(Number(s));
13
13
  }
14
14
 
15
15
  export function is_alpha(s) {
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.7.0";
2
+ export const VERSION = "0.9.4";