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.
- package/bin/tova.js +1312 -139
- package/package.json +8 -1
- package/src/analyzer/analyzer.js +539 -11
- package/src/analyzer/browser-analyzer.js +56 -8
- package/src/analyzer/deploy-analyzer.js +44 -0
- package/src/analyzer/scope.js +7 -0
- package/src/analyzer/server-analyzer.js +33 -1
- package/src/codegen/base-codegen.js +1296 -23
- package/src/codegen/browser-codegen.js +725 -20
- package/src/codegen/codegen.js +87 -5
- package/src/codegen/deploy-codegen.js +49 -0
- package/src/codegen/server-codegen.js +54 -6
- package/src/codegen/shared-codegen.js +5 -0
- package/src/codegen/theme-codegen.js +69 -0
- package/src/codegen/wasm-codegen.js +6 -0
- package/src/config/edit-toml.js +6 -2
- package/src/config/git-resolver.js +128 -0
- package/src/config/lock-file.js +57 -0
- package/src/config/module-cache.js +58 -0
- package/src/config/module-entry.js +37 -0
- package/src/config/module-path.js +63 -0
- package/src/config/pkg-errors.js +62 -0
- package/src/config/resolve.js +26 -0
- package/src/config/resolver.js +139 -0
- package/src/config/search.js +28 -0
- package/src/config/semver.js +72 -0
- package/src/config/toml.js +61 -6
- package/src/deploy/deploy.js +217 -0
- package/src/deploy/infer.js +218 -0
- package/src/deploy/provision.js +315 -0
- package/src/diagnostics/security-scorecard.js +111 -0
- package/src/lexer/lexer.js +18 -3
- package/src/lsp/server.js +482 -0
- package/src/parser/animate-ast.js +45 -0
- package/src/parser/ast.js +39 -0
- package/src/parser/browser-ast.js +19 -1
- package/src/parser/browser-parser.js +221 -4
- package/src/parser/concurrency-ast.js +15 -0
- package/src/parser/concurrency-parser.js +236 -0
- package/src/parser/deploy-ast.js +37 -0
- package/src/parser/deploy-parser.js +132 -0
- package/src/parser/parser.js +42 -5
- package/src/parser/select-ast.js +39 -0
- package/src/parser/theme-ast.js +29 -0
- package/src/parser/theme-parser.js +70 -0
- package/src/registry/plugins/concurrency-plugin.js +32 -0
- package/src/registry/plugins/deploy-plugin.js +33 -0
- package/src/registry/plugins/theme-plugin.js +20 -0
- package/src/registry/register-all.js +6 -0
- package/src/runtime/charts.js +547 -0
- package/src/runtime/embedded.js +6 -2
- package/src/runtime/reactivity.js +60 -0
- package/src/runtime/router.js +703 -295
- package/src/runtime/table.js +606 -33
- package/src/stdlib/inline.js +365 -10
- package/src/stdlib/runtime-bridge.js +152 -0
- package/src/stdlib/string.js +84 -2
- package/src/stdlib/validation.js +1 -1
- package/src/version.js +1 -1
package/src/stdlib/inline.js
CHANGED
|
@@ -60,7 +60,39 @@ export const PROPAGATE = `function __propagate(val) {
|
|
|
60
60
|
|
|
61
61
|
// Individual builtin functions for tree-shaking
|
|
62
62
|
export const BUILTIN_FUNCTIONS = {
|
|
63
|
-
print: `function print(...args) {
|
|
63
|
+
print: `function print(...args) {
|
|
64
|
+
var _noColor = typeof process !== 'undefined' && (process.env.NO_COLOR || (process.stdout && !process.stdout.isTTY));
|
|
65
|
+
var _codes = { red: '31', green: '32', yellow: '33', blue: '34', magenta: '35', cyan: '36', gray: '90', bold: '1', dim: '2', underline: '4' };
|
|
66
|
+
var _styled = function(s) {
|
|
67
|
+
if (typeof s !== 'string') return s;
|
|
68
|
+
return s.replace(/\\{(\\/|red|green|yellow|blue|magenta|cyan|gray|bold|dim|underline)\\}/g, function(_, tag) {
|
|
69
|
+
if (_noColor) return '';
|
|
70
|
+
if (tag === '/') return '\\x1b[0m';
|
|
71
|
+
return '\\x1b[' + _codes[tag] + 'm';
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
var _pretty = function(v) {
|
|
75
|
+
if (v === null || v === undefined) return v;
|
|
76
|
+
if (typeof v !== 'object') return v;
|
|
77
|
+
if (Array.isArray(v) && v.length > 0 && typeof v[0] === 'object' && v[0] !== null && !Array.isArray(v[0])) {
|
|
78
|
+
var headers = Object.keys(v[0]);
|
|
79
|
+
var rows = v.map(function(r) { return headers.map(function(h) { return String(r[h] != null ? r[h] : ''); }); });
|
|
80
|
+
var widths = headers.map(function(h, i) { return Math.max(h.length, Math.max.apply(null, rows.map(function(r) { return r[i].length; }))); });
|
|
81
|
+
var line = widths.map(function(w) { return '-'.repeat(w + 2); }).join('+');
|
|
82
|
+
var head = headers.map(function(h, i) { return ' ' + h.padEnd(widths[i]) + ' '; }).join('|');
|
|
83
|
+
var body = rows.map(function(r) { return r.map(function(c, i) { return ' ' + c.padEnd(widths[i]) + ' '; }).join('|'); }).join('\\n');
|
|
84
|
+
return head + '\\n' + line + '\\n' + body;
|
|
85
|
+
}
|
|
86
|
+
return JSON.stringify(v, null, 2);
|
|
87
|
+
};
|
|
88
|
+
if (args.length === 1) {
|
|
89
|
+
var processed = _styled(_pretty(args[0]));
|
|
90
|
+
console.log(processed);
|
|
91
|
+
} else {
|
|
92
|
+
var processed = args.map(function(a) { return _styled(a); });
|
|
93
|
+
console.log.apply(console, processed);
|
|
94
|
+
}
|
|
95
|
+
}`,
|
|
64
96
|
len: `function len(v) { if (v == null) return 0; if (typeof v === 'string' || Array.isArray(v) || ArrayBuffer.isView(v)) return v.length; if (typeof v === 'object') return Object.keys(v).length; return 0; }`,
|
|
65
97
|
range: `function range(s, e, st) { if (e === undefined) { e = s; s = 0; } if (st === undefined) st = s < e ? 1 : -1; if (st === 0) return []; const r = []; if (st > 0) { for (let i = s; i < e; i += st) r.push(i); } else { for (let i = s; i > e; i += st) r.push(i); } return r; }`,
|
|
66
98
|
enumerate: `function enumerate(a) { return a.map((v, i) => [i, v]); }`,
|
|
@@ -117,7 +149,7 @@ export const BUILTIN_FUNCTIONS = {
|
|
|
117
149
|
if (!parallel_map._pool) {
|
|
118
150
|
const { Worker } = await import("worker_threads");
|
|
119
151
|
const wc = 'const{parentPort}=require("worker_threads");parentPort.on("message",m=>{const fn=(0,eval)("("+m.f+")");try{const r=m.c.map(fn);parentPort.postMessage({i:m.i,r})}catch(e){parentPort.postMessage({i:m.i,e:e.message})}})';
|
|
120
|
-
parallel_map._pool = Array.from({length: n}, () =>
|
|
152
|
+
parallel_map._pool = Array.from({length: n}, () => new Worker(wc, {eval: true}));
|
|
121
153
|
parallel_map._cid = 0;
|
|
122
154
|
}
|
|
123
155
|
const pool = parallel_map._pool;
|
|
@@ -125,17 +157,20 @@ export const BUILTIN_FUNCTIONS = {
|
|
|
125
157
|
const fnStr = fn.toString();
|
|
126
158
|
const cid = ++parallel_map._cid;
|
|
127
159
|
const promises = [];
|
|
160
|
+
const usedWorkers = [];
|
|
128
161
|
for (let ci = 0; ci < pool.length && ci * cs < arr.length; ci++) {
|
|
129
162
|
const chunk = arr.slice(ci * cs, (ci + 1) * cs);
|
|
130
163
|
const mid = cid * 1000 + ci;
|
|
164
|
+
const w = pool[ci];
|
|
165
|
+
w.ref();
|
|
166
|
+
usedWorkers.push(w);
|
|
131
167
|
promises.push(new Promise((resolve, reject) => {
|
|
132
|
-
const w = pool[ci];
|
|
133
168
|
const h = (msg) => { if (msg.i === mid) { w.removeListener("message", h); if (msg.e) reject(new Error(msg.e)); else resolve(msg.r); } };
|
|
134
169
|
w.on("message", h);
|
|
135
170
|
w.postMessage({i: mid, c: chunk, f: fnStr});
|
|
136
171
|
}));
|
|
137
172
|
}
|
|
138
|
-
return (await Promise.all(promises)).flat();
|
|
173
|
+
try { return (await Promise.all(promises)).flat(); } finally { for (const w of usedWorkers) w.unref(); }
|
|
139
174
|
}`,
|
|
140
175
|
upper: `function upper(s) { return s.toUpperCase(); }`,
|
|
141
176
|
lower: `function lower(s) { return s.toLowerCase(); }`,
|
|
@@ -193,7 +228,7 @@ export const BUILTIN_FUNCTIONS = {
|
|
|
193
228
|
atan2: `function atan2(y, x) { return Math.atan2(y, x); }`,
|
|
194
229
|
|
|
195
230
|
// ── Logarithmic / Exponential ─────────────────────────
|
|
196
|
-
|
|
231
|
+
ln: `function ln(n) { return Math.log(n); }`,
|
|
197
232
|
log2: `function log2(n) { return Math.log2(n); }`,
|
|
198
233
|
log10: `function log10(n) { return Math.log10(n); }`,
|
|
199
234
|
exp: `function exp(n) { return Math.exp(n); }`,
|
|
@@ -237,7 +272,7 @@ Table.prototype = { get rows() { return this._rows.length; }, get columns() { re
|
|
|
237
272
|
table_agg: `function table_agg(grouped, aggregations) { if (!grouped || !grouped.__grouped) throw new Error('agg() must be called after group_by()'); const rows = []; for (const [, { key, rows: gr }] of grouped.groups) { const row = typeof key === 'object' && key !== null ? { ...key } : { _group: key }; for (const [n, fn] of Object.entries(aggregations)) { row[n] = fn(gr); } rows.push(row); } return Table(rows, rows.length > 0 ? Object.keys(rows[0]) : []); }`,
|
|
238
273
|
table_sort_by: `function table_sort_by(table, keyFn, opts) { const desc = opts && opts.desc; const rows = [...table._rows].sort((a, b) => { const ka = typeof keyFn === 'function' ? keyFn(a) : a[keyFn]; const kb = typeof keyFn === 'function' ? keyFn(b) : b[keyFn]; let c = ka < kb ? -1 : ka > kb ? 1 : 0; return desc ? -c : c; }); return Table(rows, table._columns); }`,
|
|
239
274
|
table_limit: `function table_limit(table, n) { return Table(table._rows.slice(0, n), table._columns); }`,
|
|
240
|
-
table_join: `function table_join(table, other, opts) { const { left, right, how } = opts || {}; if (!left || !right) throw new Error('join() requires left and right key functions'); const rows = []; const ri = new Map(); for (const r of other._rows) { const k = typeof right === 'function' ? right(r) : r[right]; const ks = String(k); if (!ri.has(ks)) ri.set(ks, []); ri.get(ks).push(r); } const cc = [...new Set([...table._columns, ...other._columns])]; for (const lr of table._rows) { const k = typeof left === 'function' ? left(lr) : lr[left]; const ms = ri.get(String(k)) || []; if (ms.length > 0) { for (const rr of ms) rows.push({ ...lr, ...rr }); } else if (how === 'left' || how === 'outer') { const row = { ...lr }; for (const c of other._columns) { if (!(c in row)) row[c] = null; } rows.push(row); } } return Table(rows, cc); }`,
|
|
275
|
+
table_join: `function table_join(table, other, opts) { const { left, right, how } = opts || {}; if (how === 'cross') { const rows = []; const cc = [...new Set([...table._columns, ...other._columns])]; for (const lr of table._rows) { for (const rr of other._rows) { rows.push({ ...lr, ...rr }); } } return Table(rows, cc); } if (!left || !right) throw new Error('join() requires left and right key functions'); if (how === 'anti') { const ri = new Set(); for (const r of other._rows) { ri.add(String(typeof right === 'function' ? right(r) : r[right])); } const rows = []; for (const lr of table._rows) { const k = typeof left === 'function' ? left(lr) : lr[left]; if (!ri.has(String(k))) rows.push({ ...lr }); } return Table(rows, [...table._columns]); } if (how === 'semi') { const ri = new Set(); for (const r of other._rows) { ri.add(String(typeof right === 'function' ? right(r) : r[right])); } const rows = []; for (const lr of table._rows) { const k = typeof left === 'function' ? left(lr) : lr[left]; if (ri.has(String(k))) rows.push({ ...lr }); } return Table(rows, [...table._columns]); } if (how === 'right') { const sw = table_join(other, table, { left: right, right: left, how: 'left' }); const cc = [...new Set([...table._columns, ...other._columns])]; return Table(sw._rows, cc); } const ri = new Map(); for (const r of other._rows) { const k = typeof right === 'function' ? right(r) : r[right]; const ks = String(k); if (!ri.has(ks)) ri.set(ks, []); ri.get(ks).push(r); } const cc = [...new Set([...table._columns, ...other._columns])]; const rows = []; const mrk = how === 'outer' ? new Set() : null; for (const lr of table._rows) { const k = typeof left === 'function' ? left(lr) : lr[left]; const ms = ri.get(String(k)) || []; if (ms.length > 0) { for (const rr of ms) rows.push({ ...lr, ...rr }); if (mrk) mrk.add(String(k)); } else if (how === 'left' || how === 'outer') { const row = { ...lr }; for (const c of other._columns) { if (!(c in row)) row[c] = null; } rows.push(row); } } if (how === 'outer') { for (const r of other._rows) { const k = typeof right === 'function' ? right(r) : r[right]; if (!mrk.has(String(k))) { const row = { ...r }; for (const c of table._columns) { if (!(c in row)) row[c] = null; } rows.push(row); } } } return Table(rows, cc); }`,
|
|
241
276
|
table_pivot: `function table_pivot(table, opts) { const { index, columns: colFn, values: valFn } = opts || {}; const pm = new Map(); const ac = new Set(); for (const row of table._rows) { const ik = typeof index === 'function' ? index(row) : row[index]; const col = typeof colFn === 'function' ? colFn(row) : row[colFn]; const val = typeof valFn === 'function' ? valFn(row) : row[valFn]; const ks = String(ik); if (!pm.has(ks)) pm.set(ks, { _index: ik }); pm.get(ks)[String(col)] = val; ac.add(String(col)); } return Table([...pm.values()], ['_index', ...ac]); }`,
|
|
242
277
|
table_unpivot: `function table_unpivot(table, opts) { const { id, columns: uc } = opts || {}; const cn = uc.filter(c => typeof c === 'string'); const rows = []; for (const row of table._rows) { const iv = typeof id === 'function' ? id(row) : row[id]; for (const col of cn) rows.push({ id: iv, variable: col, value: row[col] }); } return Table(rows, ['id', 'variable', 'value']); }`,
|
|
243
278
|
table_explode: `function table_explode(table, colFn) { const rows = []; for (const row of table._rows) { const arr = typeof colFn === 'function' ? colFn(row) : row[colFn]; if (Array.isArray(arr)) { const cn = typeof colFn === 'string' ? colFn : null; for (const val of arr) { const r = { ...row }; if (cn) r[cn] = val; rows.push(r); } } else { rows.push({ ...row }); } } return Table(rows, table._columns); }`,
|
|
@@ -349,6 +384,24 @@ Table.prototype = { get rows() { return this._rows.length; }, get columns() { re
|
|
|
349
384
|
agg_min: `function agg_min(fn) { return (rows) => { if (rows.length === 0) return null; let m = typeof fn === 'function' ? fn(rows[0]) : rows[0][fn]; for (let i = 1; i < rows.length; i++) { const v = typeof fn === 'function' ? fn(rows[i]) : rows[i][fn]; if (v < m) m = v; } return m; }; }`,
|
|
350
385
|
agg_max: `function agg_max(fn) { return (rows) => { if (rows.length === 0) return null; let m = typeof fn === 'function' ? fn(rows[0]) : rows[0][fn]; for (let i = 1; i < rows.length; i++) { const v = typeof fn === 'function' ? fn(rows[i]) : rows[i][fn]; if (v > m) m = v; } return m; }; }`,
|
|
351
386
|
|
|
387
|
+
// ── Window functions ─────────────────────────────────
|
|
388
|
+
win_row_number: `function win_row_number() { return (_rows, index) => index + 1; }`,
|
|
389
|
+
win_rank: `function win_rank() { return (_rows, index, ctx) => { if (index === 0) return 1; const cur = ctx.orderValues[index]; for (let i = index - 1; i >= 0; i--) { if (ctx.orderValues[i] !== cur) return i + 2; } return 1; }; }`,
|
|
390
|
+
win_dense_rank: `function win_dense_rank() { return (_rows, index, ctx) => { if (index === 0) return 1; let rank = 1; for (let i = 1; i <= index; i++) { if (ctx.orderValues[i] !== ctx.orderValues[i - 1]) rank++; } return rank; }; }`,
|
|
391
|
+
win_percent_rank: `function win_percent_rank() { return (rows, index, ctx) => { const n = ctx.partitionSize; if (n <= 1) return 0; const cur = ctx.orderValues[index]; let r = 1; if (index > 0) { for (let i = index - 1; i >= 0; i--) { if (ctx.orderValues[i] !== cur) { r = i + 2; break; } } } return (r - 1) / (n - 1); }; }`,
|
|
392
|
+
win_ntile: `function win_ntile(buckets) { return (_rows, index, ctx) => Math.floor(index * buckets / ctx.partitionSize) + 1; }`,
|
|
393
|
+
win_lag: `function win_lag(colFn, offset, defaultVal) { if (offset === undefined) offset = 1; if (defaultVal === undefined) defaultVal = null; return (rows, index) => { const t = index - offset; if (t < 0 || t >= rows.length) return defaultVal; return typeof colFn === 'function' ? colFn(rows[t]) : rows[t][colFn]; }; }`,
|
|
394
|
+
win_lead: `function win_lead(colFn, offset, defaultVal) { if (offset === undefined) offset = 1; if (defaultVal === undefined) defaultVal = null; return (rows, index) => { const t = index + offset; if (t < 0 || t >= rows.length) return defaultVal; return typeof colFn === 'function' ? colFn(rows[t]) : rows[t][colFn]; }; }`,
|
|
395
|
+
win_first_value: `function win_first_value(colFn) { return (rows) => { if (rows.length === 0) return null; return typeof colFn === 'function' ? colFn(rows[0]) : rows[0][colFn]; }; }`,
|
|
396
|
+
win_last_value: `function win_last_value(colFn) { return (rows) => { if (rows.length === 0) return null; const last = rows[rows.length - 1]; return typeof colFn === 'function' ? colFn(last) : last[colFn]; }; }`,
|
|
397
|
+
win_running_sum: `function win_running_sum(colFn) { return (rows, index) => { let s = 0; for (let i = 0; i <= index; i++) s += typeof colFn === 'function' ? colFn(rows[i]) : rows[i][colFn]; return s; }; }`,
|
|
398
|
+
win_running_count: `function win_running_count() { return (_rows, index) => index + 1; }`,
|
|
399
|
+
win_running_avg: `function win_running_avg(colFn) { return (rows, index) => { let s = 0; for (let i = 0; i <= index; i++) s += typeof colFn === 'function' ? colFn(rows[i]) : rows[i][colFn]; return s / (index + 1); }; }`,
|
|
400
|
+
win_running_min: `function win_running_min(colFn) { return (rows, index) => { let m = typeof colFn === 'function' ? colFn(rows[0]) : rows[0][colFn]; for (let i = 1; i <= index; i++) { const v = typeof colFn === 'function' ? colFn(rows[i]) : rows[i][colFn]; if (v < m) m = v; } return m; }; }`,
|
|
401
|
+
win_running_max: `function win_running_max(colFn) { return (rows, index) => { let m = typeof colFn === 'function' ? colFn(rows[0]) : rows[0][colFn]; for (let i = 1; i <= index; i++) { const v = typeof colFn === 'function' ? colFn(rows[i]) : rows[i][colFn]; if (v > m) m = v; } return m; }; }`,
|
|
402
|
+
win_moving_avg: `function win_moving_avg(colFn, windowSize) { return (rows, index) => { const start = Math.max(0, index - windowSize + 1); let s = 0; for (let i = start; i <= index; i++) s += typeof colFn === 'function' ? colFn(rows[i]) : rows[i][colFn]; return s / (index - start + 1); }; }`,
|
|
403
|
+
table_window: `function table_window(table, opts, windowFns) { const partFn = opts.partition || null; const ordFn = opts.order || null; const desc = opts.desc || false; const parts = new Map(); for (let i = 0; i < table._rows.length; i++) { const r = table._rows[i]; const k = partFn ? String(typeof partFn === 'function' ? partFn(r) : r[partFn]) : '__all__'; if (!parts.has(k)) parts.set(k, []); parts.get(k).push({ row: r, oi: i }); } if (ordFn) { for (const [, items] of parts) { items.sort((a, b) => { const ka = typeof ordFn === 'function' ? ordFn(a.row) : a.row[ordFn]; const kb = typeof ordFn === 'function' ? ordFn(b.row) : b.row[ordFn]; let c = 0; if (ka < kb) c = -1; else if (ka > kb) c = 1; return desc ? -c : c; }); } } const res = new Array(table._rows.length); for (let i = 0; i < res.length; i++) res[i] = {}; for (const [, items] of parts) { const pr = items.map(it => it.row); const ov = ordFn ? pr.map(r => typeof ordFn === 'function' ? ordFn(r) : r[ordFn]) : pr.map((_, i) => i); const ctx = { orderValues: ov, partitionSize: pr.length }; for (const [cn, wf] of Object.entries(windowFns)) { for (let idx = 0; idx < pr.length; idx++) { res[items[idx].oi][cn] = wf(pr, idx, ctx); } } } const nc = [...table._columns]; for (const cn of Object.keys(windowFns)) { if (!nc.includes(cn)) nc.push(cn); } return new Table(table._rows.map((r, i) => Object.assign({}, r, res[i])), nc); }`,
|
|
404
|
+
|
|
352
405
|
// ── Data exploration ────────────────────────────────
|
|
353
406
|
peek: `function peek(table, opts) { const o = typeof opts === 'object' ? opts : {}; console.log(table._format ? table._format(o.n || 10, o.title) : String(table)); return table; }`,
|
|
354
407
|
describe: `function describe(table) { const stats = []; for (const col of table._columns) { const vals = table._rows.map(r => r[col]).filter(v => v != null); const st = { Column: col, Type: 'Unknown', 'Non-Null': vals.length }; if (vals.length > 0) { const s = vals[0]; if (typeof s === 'number') { st.Type = Number.isInteger(s) ? 'Int' : 'Float'; st.Mean = vals.reduce((a, b) => a + b, 0) / vals.length; let mn = vals[0], mx = vals[0]; for (let i = 1; i < vals.length; i++) { if (vals[i] < mn) mn = vals[i]; if (vals[i] > mx) mx = vals[i]; } st.Min = mn; st.Max = mx; } else if (typeof s === 'string') { st.Type = 'String'; st.Unique = new Set(vals).size; } else if (typeof s === 'boolean') { st.Type = 'Bool'; } } stats.push(st); } const dt = Table(stats); console.log(dt._format(100, 'describe()')); return dt; }`,
|
|
@@ -378,7 +431,10 @@ Table.prototype = { get rows() { return this._rows.length; }, get columns() { re
|
|
|
378
431
|
try { const data = JSON.parse(text); if (Array.isArray(data)) return Table(data); return data; } catch { return __parseCSV(text, options); }
|
|
379
432
|
}
|
|
380
433
|
const fs = await import('fs'); const path = await import('path');
|
|
381
|
-
const ext = path.extname(source).toLowerCase();
|
|
434
|
+
const ext = path.extname(source).toLowerCase();
|
|
435
|
+
if (ext === '.parquet') return readParquet(source);
|
|
436
|
+
if (ext === '.xlsx') return readExcel(source, options);
|
|
437
|
+
const text = fs.readFileSync(source, 'utf-8');
|
|
382
438
|
if (ext === '.csv') return __parseCSV(text, options);
|
|
383
439
|
if (ext === '.tsv') return __parseCSV(text, { ...options, delimiter: '\\t' });
|
|
384
440
|
if (ext === '.json') { const data = JSON.parse(text); if (Array.isArray(data)) return Table(data); return data; }
|
|
@@ -388,6 +444,8 @@ Table.prototype = { get rows() { return this._rows.length; }, get columns() { re
|
|
|
388
444
|
write: `async function write(data, destination, opts) {
|
|
389
445
|
const fs = await import('fs'); const path = await import('path');
|
|
390
446
|
const ext = path.extname(destination).toLowerCase();
|
|
447
|
+
if (ext === '.parquet') { return writeParquet(data, destination, opts); }
|
|
448
|
+
if (ext === '.xlsx') { return writeExcel(data, destination, opts); }
|
|
391
449
|
const isTable = data && data._rows && data._columns;
|
|
392
450
|
const td = isTable ? data : (Array.isArray(data) ? Table(data) : null);
|
|
393
451
|
let content;
|
|
@@ -513,7 +571,7 @@ Table.prototype = { get rows() { return this._rows.length; }, get columns() { re
|
|
|
513
571
|
// ── Validation ─────────────────────────────────────────
|
|
514
572
|
is_email: `function is_email(s) { return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(s); }`,
|
|
515
573
|
is_url: `function is_url(s) { try { new URL(s); return true; } catch { return false; } }`,
|
|
516
|
-
is_numeric: `function is_numeric(s) { return typeof s === 'string' && s.length > 0 && !isNaN(Number(s)); }`,
|
|
574
|
+
is_numeric: `function is_numeric(s) { return typeof s === 'string' && s.length > 0 && s.trim().length > 0 && !isNaN(Number(s)); }`,
|
|
517
575
|
is_alpha: `function is_alpha(s) { return /^[a-zA-Z]+$/.test(s); }`,
|
|
518
576
|
is_alphanumeric: `function is_alphanumeric(s) { return /^[a-zA-Z0-9]+$/.test(s); }`,
|
|
519
577
|
is_uuid: `function is_uuid(s) { return /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(s); }`,
|
|
@@ -578,11 +636,11 @@ Table.prototype = { get rows() { return this._rows.length; }, get columns() { re
|
|
|
578
636
|
flip: `function flip(fn) { return function(a, b, ...rest) { return fn(b, a, ...rest); }; }`,
|
|
579
637
|
|
|
580
638
|
// ── Encoding (extended) ────────────────────────────────
|
|
581
|
-
hex_encode: `function hex_encode(s) { let r = ''; for (let i = 0; i < s.length; i++) r += s.charCodeAt(i).toString(16).padStart(2, '0'); return r; }`,
|
|
639
|
+
hex_encode: `function hex_encode(s) { let r = ''; if (ArrayBuffer.isView(s) || s instanceof ArrayBuffer) { const u = ArrayBuffer.isView(s) ? s : new Uint8Array(s); for (let i = 0; i < u.length; i++) r += u[i].toString(16).padStart(2, '0'); return r; } for (let i = 0; i < s.length; i++) r += s.charCodeAt(i).toString(16).padStart(2, '0'); return r; }`,
|
|
582
640
|
hex_decode: `function hex_decode(s) { let r = ''; for (let i = 0; i < s.length; i += 2) r += String.fromCharCode(parseInt(s.substr(i, 2), 16)); return r; }`,
|
|
583
641
|
|
|
584
642
|
// ── String (extended) ──────────────────────────────────
|
|
585
|
-
fmt: `function fmt(template, ...args) {
|
|
643
|
+
fmt: `function fmt(template, ...args) { var named = args.length === 1 && args[0] !== null && typeof args[0] === 'object' && !Array.isArray(args[0]) && !(args[0] instanceof Date); var obj = named ? args[0] : null; var ai = 0, result = '', pos = 0, len = template.length; while (pos < len) { if (pos + 1 < len && template[pos] === '{' && template[pos + 1] === '{') { result += '{'; pos += 2; continue; } if (pos + 1 < len && template[pos] === '}' && template[pos + 1] === '}') { result += '}'; pos += 2; continue; } if (template[pos] === '{') { var close = template.indexOf('}', pos + 1); if (close === -1) { result += template[pos]; pos++; continue; } var inner = template.substring(pos + 1, close); pos = close + 1; var colonIdx = inner.indexOf(':'); var key = colonIdx >= 0 ? inner.substring(0, colonIdx) : inner; var spec = colonIdx >= 0 ? inner.substring(colonIdx + 1) : ''; var val; if (named && key.length > 0) { val = obj[key]; if (val === undefined) { result += '{' + inner + '}'; continue; } } else if (key.length === 0) { if (ai < args.length) { val = args[ai++]; } else { result += '{}'; continue; } } else { if (ai < args.length) { val = args[ai++]; } else { result += '{' + inner + '}'; continue; } } if (!spec) { result += String(val); continue; } var si = 0, fill = ' ', align = '', sign = '', comma = false, width = 0, hasWidth = false, precision = -1, type = ''; if (si + 1 < spec.length && (spec[si + 1] === '<' || spec[si + 1] === '>' || spec[si + 1] === '^')) { fill = spec[si]; align = spec[si + 1]; si += 2; } else if (si < spec.length && (spec[si] === '<' || spec[si] === '>' || spec[si] === '^')) { align = spec[si]; si += 1; } if (si < spec.length && (spec[si] === '+' || spec[si] === '-' || spec[si] === ' ')) { sign = spec[si]; si += 1; } while (si < spec.length && spec[si] >= '0' && spec[si] <= '9') { width = width * 10 + (spec.charCodeAt(si) - 48); hasWidth = true; si += 1; } if (si < spec.length && spec[si] === ',') { comma = true; si += 1; } 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; } } if (si < spec.length) { type = spec[si]; } var formatted, numVal = typeof val === 'number' ? val : Number(val); switch (type) { case 'b': formatted = (numVal >>> 0).toString(2); if (numVal === 0) formatted = '0'; break; case 'o': formatted = (numVal >>> 0).toString(8); if (numVal === 0) formatted = '0'; break; case 'x': formatted = (numVal >>> 0).toString(16); if (numVal === 0) formatted = '0'; break; case 'X': formatted = (numVal >>> 0).toString(16).toUpperCase(); if (numVal === 0) formatted = '0'; break; case 'f': formatted = numVal.toFixed(precision >= 0 ? precision : 6); break; case '%': { var pct = numVal * 100; formatted = precision >= 0 ? pct.toFixed(precision) + '%' : (Math.round(pct * 1e10) / 1e10).toString() + '%'; break; } case '$': { var abs = Math.abs(numVal), dollars = abs.toFixed(2), dotIdx2 = dollars.indexOf('.'), intPart2 = dollars.substring(0, dotIdx2), decPart2 = dollars.substring(dotIdx2); var withCommas2 = ''; for (var j2 = 0; j2 < intPart2.length; j2++) { if (j2 > 0 && (intPart2.length - j2) % 3 === 0) withCommas2 += ','; withCommas2 += intPart2[j2]; } formatted = (numVal < 0 ? '-' : '') + '$' + withCommas2 + decPart2; break; } case 's': formatted = String(val); if (precision >= 0) formatted = formatted.substring(0, precision); break; default: if (typeof val === 'number' && precision >= 0 && !type) formatted = numVal.toFixed(precision); else formatted = String(val); break; } if (comma && type !== '$') { var dIdx = formatted.indexOf('.'), iPart = dIdx >= 0 ? formatted.substring(0, dIdx) : formatted, dPart = dIdx >= 0 ? formatted.substring(dIdx) : ''; var signChar = '', digits = iPart; if (digits[0] === '-' || digits[0] === '+') { signChar = digits[0]; digits = digits.substring(1); } var withC = ''; for (var j = 0; j < digits.length; j++) { if (j > 0 && (digits.length - j) % 3 === 0) withC += ','; withC += digits[j]; } formatted = signChar + withC + dPart; } if (sign && type !== '$' && type !== '%') { if (typeof val === 'number') { var s = formatted; if (s[0] === '-' || s[0] === '+') { s = s.substring(1); } if (numVal >= 0) { if (sign === '+') formatted = '+' + s; else if (sign === ' ') formatted = ' ' + s; else formatted = s; } else { formatted = '-' + s; } } } if (hasWidth && formatted.length < width) { var pad = width - formatted.length, a = align || '>'; if (a === '<') formatted = formatted + fill.repeat(pad); else if (a === '^') { var left = Math.floor(pad / 2); formatted = fill.repeat(left) + formatted + fill.repeat(pad - left); } else formatted = fill.repeat(pad) + formatted; } result += formatted; continue; } result += template[pos]; pos++; } return result; }`,
|
|
586
644
|
|
|
587
645
|
// ── Scripting: Environment & CLI ──────────────────────
|
|
588
646
|
env: `function env(key, fallback) { if (key === undefined) return { ...process.env }; const v = process.env[key]; return v !== undefined ? v : (fallback !== undefined ? fallback : null); }`,
|
|
@@ -989,6 +1047,19 @@ Table.prototype = { get rows() { return this._rows.length; }, get columns() { re
|
|
|
989
1047
|
pretty(v) { return JSON.stringify(v, null, 2); }
|
|
990
1048
|
});`,
|
|
991
1049
|
|
|
1050
|
+
crypto: `const crypto = Object.freeze({
|
|
1051
|
+
sha256(data) { const c = require('crypto'); return c.createHash('sha256').update(typeof data === 'string' ? data : Buffer.from(data)).digest('hex'); },
|
|
1052
|
+
sha512(data) { const c = require('crypto'); return c.createHash('sha512').update(typeof data === 'string' ? data : Buffer.from(data)).digest('hex'); },
|
|
1053
|
+
hmac(algo, key, data) { const c = require('crypto'); return c.createHmac(algo, key).update(data).digest('hex'); },
|
|
1054
|
+
random_bytes(n) { return new Uint8Array(require('crypto').randomBytes(n)); },
|
|
1055
|
+
random_int(min, max) { return min + Math.floor(Math.random() * (max - min + 1)); },
|
|
1056
|
+
hash_password(password) { try { const c = require('crypto'); const salt = c.randomBytes(16); const hash = c.scryptSync(password, salt, 64); return Ok(salt.toString('hex') + ':' + hash.toString('hex')); } catch (e) { return Err(e.message); } },
|
|
1057
|
+
verify_password(password, stored) { try { const c = require('crypto'); const [saltHex, hashHex] = stored.split(':'); const salt = Buffer.from(saltHex, 'hex'); const hash = Buffer.from(hashHex, 'hex'); const derived = c.scryptSync(password, salt, 64); return c.timingSafeEqual(hash, derived); } catch { return false; } },
|
|
1058
|
+
encrypt(plaintext, key) { try { const c = require('crypto'); const iv = c.randomBytes(12); const kb = typeof key === 'string' ? Buffer.from(key, 'utf-8').slice(0, 32) : key; const cipher = c.createCipheriv('aes-256-gcm', kb, iv); let enc = cipher.update(plaintext, 'utf8', 'hex'); enc += cipher.final('hex'); const tag = cipher.getAuthTag().toString('hex'); return Ok(iv.toString('hex') + ':' + tag + ':' + enc); } catch (e) { return Err(e.message); } },
|
|
1059
|
+
decrypt(ciphertext, key) { try { const c = require('crypto'); const [ivHex, tagHex, enc] = ciphertext.split(':'); const iv = Buffer.from(ivHex, 'hex'); const tag = Buffer.from(tagHex, 'hex'); const kb = typeof key === 'string' ? Buffer.from(key, 'utf-8').slice(0, 32) : key; const decipher = c.createDecipheriv('aes-256-gcm', kb, iv); decipher.setAuthTag(tag); let dec = decipher.update(enc, 'hex', 'utf8'); dec += decipher.final('utf8'); return Ok(dec); } catch (e) { return Err(e.message); } },
|
|
1060
|
+
constant_time_equal(a, b) { try { const ba = Buffer.from(a); const bb = Buffer.from(b); if (ba.length !== bb.length) return false; return require('crypto').timingSafeEqual(ba, bb); } catch { return false; } }
|
|
1061
|
+
});`,
|
|
1062
|
+
|
|
992
1063
|
fs: `const fs = Object.freeze({
|
|
993
1064
|
read_text(path, enc) { try { return Ok(require('fs').readFileSync(path, enc || 'utf-8')); } catch (e) { return Err(e.message); } },
|
|
994
1065
|
write_text(path, content, opts) { try { const f = require('fs'); if (opts && opts.append) f.appendFileSync(path, content); else f.writeFileSync(path, content); return Ok(path); } catch (e) { return Err(e.message); } },
|
|
@@ -1010,6 +1081,48 @@ Table.prototype = { get rows() { return this._rows.length; }, get columns() { re
|
|
|
1010
1081
|
build_query(obj) { return Object.entries(obj).map(([k, v]) => encodeURIComponent(k) + '=' + encodeURIComponent(v)).join('&'); }
|
|
1011
1082
|
});`,
|
|
1012
1083
|
|
|
1084
|
+
http: `const http = Object.freeze({
|
|
1085
|
+
async _request(method, url, body, opts) {
|
|
1086
|
+
var o = opts || {};
|
|
1087
|
+
var headers = o.headers ? { ...o.headers } : {};
|
|
1088
|
+
if (o.bearer) headers['Authorization'] = 'Bearer ' + o.bearer;
|
|
1089
|
+
if (o.params) { var _qs = new URLSearchParams(o.params).toString(); if (_qs) url += (url.includes('?') ? '&' : '?') + _qs; }
|
|
1090
|
+
if (typeof FormData !== 'undefined' && body instanceof FormData) { delete headers['Content-Type']; }
|
|
1091
|
+
else if (body && typeof body === 'object' && body.__form) { var _fd = new FormData(); Object.keys(body).forEach(function(k) { if (k !== '__form') _fd.append(k, body[k]); }); body = _fd; delete headers['Content-Type']; }
|
|
1092
|
+
else if (body && typeof body === 'object' && !(body instanceof ArrayBuffer) && !(body instanceof Uint8Array) && !headers['Content-Type']) { headers['Content-Type'] = 'application/json'; body = JSON.stringify(body); }
|
|
1093
|
+
var timeout = o.timeout || 30000;
|
|
1094
|
+
var retries = o.retries || 0;
|
|
1095
|
+
var retryDelay = o.retry_delay || 1000;
|
|
1096
|
+
var attempt = 0;
|
|
1097
|
+
while (true) {
|
|
1098
|
+
try {
|
|
1099
|
+
var controller = new AbortController();
|
|
1100
|
+
var timer = setTimeout(function() { controller.abort(); }, timeout);
|
|
1101
|
+
var resp = await fetch(url, { method: method, headers: headers, body: method !== 'GET' && method !== 'HEAD' ? body : undefined, signal: controller.signal, redirect: o.follow_redirects === false ? 'manual' : 'follow' });
|
|
1102
|
+
clearTimeout(timer);
|
|
1103
|
+
var respHeaders = {};
|
|
1104
|
+
resp.headers.forEach(function(v, k) { respHeaders[k] = v; });
|
|
1105
|
+
if (o.stream) { return Ok({ status: resp.status, headers: respHeaders, body: resp.body, ok: resp.ok }); }
|
|
1106
|
+
var respBody;
|
|
1107
|
+
var ct = resp.headers.get('content-type') || '';
|
|
1108
|
+
if (ct.includes('application/json')) { try { respBody = await resp.json(); } catch(e) { respBody = await resp.text(); } }
|
|
1109
|
+
else { respBody = await resp.text(); }
|
|
1110
|
+
return Ok({ status: resp.status, headers: respHeaders, body: respBody, ok: resp.ok, json: function() { try { return Ok(typeof respBody === 'string' ? JSON.parse(respBody) : respBody); } catch (e) { return Err(e.message); } } });
|
|
1111
|
+
} catch (e) {
|
|
1112
|
+
if (attempt < retries) { attempt++; await new Promise(function(r) { setTimeout(r, retryDelay * attempt); }); continue; }
|
|
1113
|
+
return Err(e.name === 'AbortError' ? 'Timeout after ' + timeout + 'ms' : e.message);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
},
|
|
1117
|
+
get(url, opts) { return http._request('GET', url, null, opts); },
|
|
1118
|
+
post(url, body, opts) { return http._request('POST', url, body, opts); },
|
|
1119
|
+
put(url, body, opts) { return http._request('PUT', url, body, opts); },
|
|
1120
|
+
patch(url, body, opts) { return http._request('PATCH', url, body, opts); },
|
|
1121
|
+
delete(url, opts) { return http._request('DELETE', url, null, opts); },
|
|
1122
|
+
head(url, opts) { return http._request('HEAD', url, null, opts); },
|
|
1123
|
+
get_stream(url, opts) { return http._request('GET', url, null, Object.assign({}, opts, { stream: true })); }
|
|
1124
|
+
})`,
|
|
1125
|
+
|
|
1013
1126
|
// ── Channel-based async ───────────────────────────────
|
|
1014
1127
|
Channel: `class Channel {
|
|
1015
1128
|
constructor(capacity) {
|
|
@@ -1054,6 +1167,35 @@ Table.prototype = { get rows() { return this._rows.length; }, get columns() { re
|
|
|
1054
1167
|
this._recvWaiters.push(resolve);
|
|
1055
1168
|
}.bind(this));
|
|
1056
1169
|
}
|
|
1170
|
+
_tryReceive() {
|
|
1171
|
+
if (this._buffer.length > 0) {
|
|
1172
|
+
const value = this._buffer.shift();
|
|
1173
|
+
if (this._sendWaiters.length > 0) {
|
|
1174
|
+
const waiter = this._sendWaiters.shift();
|
|
1175
|
+
this._buffer.push(waiter.value);
|
|
1176
|
+
waiter.resolve();
|
|
1177
|
+
}
|
|
1178
|
+
return Some(value);
|
|
1179
|
+
}
|
|
1180
|
+
if (this._sendWaiters.length > 0) {
|
|
1181
|
+
const waiter = this._sendWaiters.shift();
|
|
1182
|
+
waiter.resolve();
|
|
1183
|
+
return Some(waiter.value);
|
|
1184
|
+
}
|
|
1185
|
+
return None;
|
|
1186
|
+
}
|
|
1187
|
+
_trySend(value) {
|
|
1188
|
+
if (this._recvWaiters.length > 0) {
|
|
1189
|
+
const waiter = this._recvWaiters.shift();
|
|
1190
|
+
waiter(Some(value));
|
|
1191
|
+
return true;
|
|
1192
|
+
}
|
|
1193
|
+
if (this._capacity > 0 && this._buffer.length < this._capacity) {
|
|
1194
|
+
this._buffer.push(value);
|
|
1195
|
+
return true;
|
|
1196
|
+
}
|
|
1197
|
+
return false;
|
|
1198
|
+
}
|
|
1057
1199
|
close() {
|
|
1058
1200
|
this._closed = true;
|
|
1059
1201
|
for (const waiter of this._recvWaiters) waiter(None);
|
|
@@ -1195,6 +1337,24 @@ Table.prototype = { get rows() { return this._rows.length; }, get columns() { re
|
|
|
1195
1337
|
OrderedDict, DefaultDict, Counter, Deque
|
|
1196
1338
|
});`,
|
|
1197
1339
|
|
|
1340
|
+
// ── LRU Cache ─────────────────────────────────────────
|
|
1341
|
+
LRUCache: `class LRUCache {
|
|
1342
|
+
constructor(maxSize, ttl) { this._max = maxSize; this._ttl = ttl || 0; this._map = new Map(); this._hits = 0; this._misses = 0; }
|
|
1343
|
+
get(key) { var entry = this._map.get(key); if (\!entry) { this._misses++; return None; } if (this._ttl > 0 && Date.now() - entry.t > this._ttl) { this._map.delete(key); this._misses++; return None; } this._map.delete(key); this._map.set(key, entry); this._hits++; return Some(entry.v); }
|
|
1344
|
+
set(key, value) { if (this._map.has(key)) this._map.delete(key); else if (this._map.size >= this._max) { var first = this._map.keys().next().value; this._map.delete(first); } this._map.set(key, { v: value, t: Date.now() }); }
|
|
1345
|
+
has(key) { if (\!this._map.has(key)) return false; if (this._ttl > 0) { var entry = this._map.get(key); if (Date.now() - entry.t > this._ttl) { this._map.delete(key); return false; } } return true; }
|
|
1346
|
+
delete(key) { return this._map.delete(key); }
|
|
1347
|
+
clear() { this._map.clear(); this._hits = 0; this._misses = 0; }
|
|
1348
|
+
size() { return this._map.size; }
|
|
1349
|
+
keys() { return [...this._map.keys()]; }
|
|
1350
|
+
stats() { var total = this._hits + this._misses; return { hits: this._hits, misses: this._misses, hit_rate: total > 0 ? this._hits / total : 0 }; }
|
|
1351
|
+
}`,
|
|
1352
|
+
|
|
1353
|
+
cache: `const cache = Object.freeze({
|
|
1354
|
+
lru(maxSize) { return new LRUCache(maxSize, 0); },
|
|
1355
|
+
ttl(maxSize, ttlMs) { return new LRUCache(maxSize, ttlMs); }
|
|
1356
|
+
})`,
|
|
1357
|
+
|
|
1198
1358
|
// ─── Typed numeric array functions for @fast mode ───────────────
|
|
1199
1359
|
|
|
1200
1360
|
typed_zeros: `function typed_zeros(n, Type) {
|
|
@@ -1290,6 +1450,172 @@ Table.prototype = { get rows() { return this._rows.length; }, get columns() { re
|
|
|
1290
1450
|
out.sort((a, b) => a - b);
|
|
1291
1451
|
return out;
|
|
1292
1452
|
}`,
|
|
1453
|
+
|
|
1454
|
+
// ── Logging Namespace ──────────────────────────────────
|
|
1455
|
+
log: `var log = (function() {
|
|
1456
|
+
var _level = 1;
|
|
1457
|
+
var _levels = { debug: 0, info: 1, warn: 2, error: 3, silent: 4 };
|
|
1458
|
+
var _format = 'pretty';
|
|
1459
|
+
var _noColor = typeof process !== 'undefined' && (process.env.NO_COLOR || (process.stdout && !process.stdout.isTTY));
|
|
1460
|
+
var _colors = { debug: '36', info: '32', warn: '33', error: '31' };
|
|
1461
|
+
var _labels = { debug: 'DBG', info: 'INF', warn: 'WRN', error: 'ERR' };
|
|
1462
|
+
function _emit(lvl, context, msg, data) {
|
|
1463
|
+
if (_levels[lvl] < _level) return;
|
|
1464
|
+
var consoleFn = lvl === 'error' ? console.error : lvl === 'warn' ? console.warn : lvl === 'debug' ? (console.debug || console.log) : console.log;
|
|
1465
|
+
if (_format === 'json') {
|
|
1466
|
+
var obj = { level: lvl, msg: msg, timestamp: new Date().toISOString() };
|
|
1467
|
+
if (context) Object.assign(obj, context);
|
|
1468
|
+
if (data && typeof data === 'object') Object.assign(obj, data);
|
|
1469
|
+
consoleFn(JSON.stringify(obj));
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
var ts = new Date().toISOString().slice(11, 19);
|
|
1473
|
+
var label = _labels[lvl];
|
|
1474
|
+
if (!_noColor) label = '\\x1b[' + _colors[lvl] + 'm' + label + '\\x1b[0m';
|
|
1475
|
+
var parts = [ts, label, msg];
|
|
1476
|
+
if (data !== undefined) parts.push(typeof data === 'object' ? JSON.stringify(data) : String(data));
|
|
1477
|
+
if (context) parts.push(JSON.stringify(context));
|
|
1478
|
+
consoleFn(parts.join(' '));
|
|
1479
|
+
}
|
|
1480
|
+
function _makeLogger(ctx) {
|
|
1481
|
+
return {
|
|
1482
|
+
debug: function(msg, data) { _emit('debug', ctx, msg, data); },
|
|
1483
|
+
info: function(msg, data) { _emit('info', ctx, msg, data); },
|
|
1484
|
+
warn: function(msg, data) { _emit('warn', ctx, msg, data); },
|
|
1485
|
+
error: function(msg, data) { _emit('error', ctx, msg, data); },
|
|
1486
|
+
level: function(l) { _level = _levels[l] !== undefined ? _levels[l] : 1; },
|
|
1487
|
+
format: function(f) { _format = f; },
|
|
1488
|
+
with: function(extra) { var merged = ctx ? Object.assign({}, ctx, extra) : extra; return _makeLogger(merged); }
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
return _makeLogger(null);
|
|
1492
|
+
})()`,
|
|
1493
|
+
// ── Sampling ──────────────────────────────────────────
|
|
1494
|
+
__xorshift128: `function __xorshift128(seed) { let s = [seed, seed ^ 0xDEADBEEF, seed ^ 0x12345678, seed ^ 0x87654321]; return function() { let t = s[3]; t ^= t << 11; t ^= t >>> 8; s[3] = s[2]; s[2] = s[1]; s[1] = s[0]; t ^= s[0]; t ^= s[0] >>> 19; s[0] = t; return (t >>> 0) / 4294967296; }; }`,
|
|
1495
|
+
table_sample: `function table_sample(table, n, opts) { var total = table._rows.length; var k = n < 1 ? Math.floor(n * total) : Math.min(n, total); if (k <= 0) return Table([], table._columns); if (k >= total) return Table([].concat(table._rows), table._columns); var rng = opts && opts.seed != null ? __xorshift128(opts.seed) : function() { return Math.random(); }; var indices = Array.from({ length: total }, function(_, i) { return i; }); for (var i = 0; i < k; i++) { var j = i + Math.floor(rng() * (total - i)); var tmp = indices[i]; indices[i] = indices[j]; indices[j] = tmp; } var rows = []; for (var i = 0; i < k; i++) rows.push(table._rows[indices[i]]); return Table(rows, table._columns); }`,
|
|
1496
|
+
table_stratified_sample: `function table_stratified_sample(table, keyFn, n, opts) { var groups = new Map(); for (var ri = 0; ri < table._rows.length; ri++) { var row = table._rows[ri]; var key = String(typeof keyFn === 'function' ? keyFn(row) : row[keyFn]); if (!groups.has(key)) groups.set(key, []); groups.get(key).push(row); } var allRows = []; var gi = 0; groups.forEach(function(gr) { var gt = Table(gr, table._columns); var go = opts && opts.seed != null ? { seed: opts.seed + gi * 7919 } : {}; var s = table_sample(gt, n, go); for (var si = 0; si < s._rows.length; si++) allRows.push(s._rows[si]); gi++; }); return Table(allRows, table._columns); }`,
|
|
1497
|
+
|
|
1498
|
+
// ── SQLite Connector ──────────────────────────────────
|
|
1499
|
+
sqlite: `function sqlite(path) { var Database; try { Database = typeof Bun !== 'undefined' ? require('bun:sqlite').Database : require('better-sqlite3'); } catch(e) { throw new Error('SQLite requires Bun (built-in) or "better-sqlite3" package under Node'); } var db = new Database(path); function _inferType(v) { if (v === null || v === undefined) return 'TEXT'; if (typeof v === 'boolean') return 'INTEGER'; if (typeof v === 'number') return Number.isInteger(v) ? 'INTEGER' : 'REAL'; return 'TEXT'; } return { _isTovaSqlite: true, query: function(sql, params) { var stmt = db.prepare(sql); var rows = params ? stmt.all.apply(stmt, params) : stmt.all(); return Table(rows); }, exec: function(sql, params) { var stmt = db.prepare(sql); var result = params ? stmt.run.apply(stmt, params) : stmt.run(); return { changes: result.changes }; }, writeTable: function(tableData, tableName, opts) { var t = tableData._rows ? tableData : Table(tableData); if (t._rows.length === 0) return; if (!opts || !opts.append) { db.run('DROP TABLE IF EXISTS "' + tableName + '"'); var colDefs = t._columns.map(function(c) { return '"' + c + '" ' + _inferType(t._rows[0][c]); }).join(', '); db.run('CREATE TABLE "' + tableName + '" (' + colDefs + ')'); } var ph = t._columns.map(function() { return '?'; }).join(', '); var cols = t._columns.map(function(c) { return '"' + c + '"'; }).join(', '); var ins = db.prepare('INSERT INTO "' + tableName + '" (' + cols + ') VALUES (' + ph + ')'); var tx = db.transaction(function(rows) { for (var i = 0; i < rows.length; i++) { var vals = t._columns.map(function(c) { var v = rows[i][c]; if (v === undefined || v === null) return null; if (typeof v === 'boolean') return v ? 1 : 0; return v; }); ins.run.apply(ins, vals); } }); tx(t._rows); }, close: function() { db.close(); } }; }`,
|
|
1500
|
+
|
|
1501
|
+
// ── SVG Charting ──────────────────────────────────────────
|
|
1502
|
+
__chart_helpers: `var __chart_PALETTE = ['#4f46e5', '#059669', '#d97706', '#dc2626', '#7c3aed', '#0891b2', '#be185d', '#65a30d'];
|
|
1503
|
+
var __chart_DEFAULT_MARGIN = { top: 40, right: 20, bottom: 60, left: 70 };
|
|
1504
|
+
function __chart_esc(s) { return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); }
|
|
1505
|
+
function __chart_getRows(data) { if (data && data._rows) return data._rows; if (Array.isArray(data)) return data; return []; }
|
|
1506
|
+
function __chart_niceTicks(mn, mx, count) { if (count === undefined) count = 5; if (mn === mx) { mn = mn - 1; mx = mx + 1; } var range = mx - mn; var roughStep = range / count; var mag = Math.pow(10, Math.floor(Math.log10(roughStep))); var cands = [1, 2, 5, 10]; var step = mag; for (var i = 0; i < cands.length; i++) { if (cands[i] * mag >= roughStep) { step = cands[i] * mag; break; } } var start = Math.floor(mn / step) * step; var ticks = []; for (var v = start; v <= mx + step * 0.5; v += step) { ticks.push(Math.round(v * 1e10) / 1e10); } return ticks; }
|
|
1507
|
+
function __chart_formatNum(n) { if (Number.isInteger(n)) return String(n); if (Math.abs(n) >= 1000) return String(Math.round(n)); return n.toFixed(1); }
|
|
1508
|
+
function __chart_empty(w, h, msg) { return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' + w + ' ' + h + '" width="' + w + '" height="' + h + '" style="font-family:system-ui,sans-serif"><text x="' + (w / 2) + '" y="' + (h / 2) + '" text-anchor="middle" fill="#888" font-size="14">' + __chart_esc(msg || 'No data') + '</text></svg>'; }`,
|
|
1509
|
+
|
|
1510
|
+
bar_chart: `function bar_chart(data, opts) { if (!opts) opts = {}; var rows = __chart_getRows(data); var width = opts.width || 600; var height = opts.height || 400; if (rows.length === 0) return __chart_empty(width, height, 'No data'); var xFn = opts.x; var yFn = opts.y; var title = opts.title || ''; var clr = opts.color || __chart_PALETTE[0]; var margin = { top: title ? 50 : 40, right: 20, bottom: 60, left: 70 }; var labels = rows.map(function(r) { return String(xFn(r)); }); var values = rows.map(function(r) { return Number(yFn(r)); }); var plotW = width - margin.left - margin.right; var plotH = height - margin.top - margin.bottom; var yMax = Math.max.apply(null, values); var ticks = __chart_niceTicks(0, yMax); var scaleMax = ticks[ticks.length - 1]; var barW = plotW / labels.length; var innerW = barW * 0.85; var p = []; p.push('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' + width + ' ' + height + '" width="' + width + '" height="' + height + '" style="font-family:system-ui,sans-serif">'); if (title) p.push('<text x="' + (width / 2) + '" y="24" text-anchor="middle" font-size="16" font-weight="bold" fill="#111">' + __chart_esc(title) + '</text>'); for (var ti = 0; ti < ticks.length; ti++) { var t = ticks[ti]; var ty = margin.top + plotH - (t / scaleMax) * plotH; p.push('<line x1="' + margin.left + '" y1="' + ty + '" x2="' + (margin.left + plotW) + '" y2="' + ty + '" stroke="#e5e7eb" stroke-width="1"/>'); p.push('<text x="' + (margin.left - 8) + '" y="' + (ty + 4) + '" text-anchor="end" font-size="11" fill="#666">' + __chart_formatNum(t) + '</text>'); } for (var i = 0; i < labels.length; i++) { var barH = scaleMax > 0 ? (values[i] / scaleMax) * plotH : 0; var bx = margin.left + i * barW + (barW - innerW) / 2; var by = margin.top + plotH - barH; var bc = Array.isArray(clr) ? clr[i % clr.length] : (opts.colors ? opts.colors[i % opts.colors.length] : clr); p.push('<rect x="' + bx + '" y="' + by + '" width="' + innerW + '" height="' + barH + '" fill="' + bc + '" rx="2"/>'); } p.push('<line x1="' + margin.left + '" y1="' + (margin.top + plotH) + '" x2="' + (margin.left + plotW) + '" y2="' + (margin.top + plotH) + '" stroke="#9ca3af" stroke-width="1"/>'); var rot = labels.length > 6; for (var i = 0; i < labels.length; i++) { var lx = margin.left + i * barW + barW / 2; var ly = margin.top + plotH + 16; if (rot) { p.push('<text x="' + lx + '" y="' + ly + '" text-anchor="end" font-size="11" fill="#666" transform="rotate(-45 ' + lx + ' ' + ly + ')">' + __chart_esc(labels[i]) + '</text>'); } else { p.push('<text x="' + lx + '" y="' + ly + '" text-anchor="middle" font-size="11" fill="#666">' + __chart_esc(labels[i]) + '</text>'); } } p.push('<line x1="' + margin.left + '" y1="' + margin.top + '" x2="' + margin.left + '" y2="' + (margin.top + plotH) + '" stroke="#9ca3af" stroke-width="1"/>'); p.push('</svg>'); return p.join('\\n'); }`,
|
|
1511
|
+
|
|
1512
|
+
line_chart: `function line_chart(data, opts) { if (!opts) opts = {}; var rows = __chart_getRows(data); var width = opts.width || 600; var height = opts.height || 400; if (rows.length === 0) return __chart_empty(width, height, 'No data'); var xFn = opts.x; var yFn = opts.y; var title = opts.title || ''; var clr = opts.color || __chart_PALETTE[0]; var showPts = opts.points || false; var margin = { top: title ? 50 : 40, right: 20, bottom: 60, left: 70 }; var xVals = rows.map(function(r) { return xFn(r); }); var yVals = rows.map(function(r) { return Number(yFn(r)); }); var plotW = width - margin.left - margin.right; var plotH = height - margin.top - margin.bottom; var xNum = xVals.every(function(v) { return typeof v === 'number' && !isNaN(v); }); var xPos; if (xNum) { var xMn = Math.min.apply(null, xVals); var xMx = Math.max.apply(null, xVals); var xR = xMx - xMn || 1; xPos = xVals.map(function(v) { return margin.left + ((v - xMn) / xR) * plotW; }); } else { var n = xVals.length; xPos = xVals.map(function(_, i) { return margin.left + (n > 1 ? (i / (n - 1)) * plotW : plotW / 2); }); } var yMn = Math.min.apply(null, yVals); var yMx = Math.max.apply(null, yVals); var ticks = __chart_niceTicks(yMn > 0 ? 0 : yMn, yMx); var sMn = ticks[0]; var sMx = ticks[ticks.length - 1]; var sR = sMx - sMn || 1; var yPos = yVals.map(function(v) { return margin.top + plotH - ((v - sMn) / sR) * plotH; }); var p = []; p.push('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' + width + ' ' + height + '" width="' + width + '" height="' + height + '" style="font-family:system-ui,sans-serif">'); if (title) p.push('<text x="' + (width / 2) + '" y="24" text-anchor="middle" font-size="16" font-weight="bold" fill="#111">' + __chart_esc(title) + '</text>'); for (var ti = 0; ti < ticks.length; ti++) { var t = ticks[ti]; var ty = margin.top + plotH - ((t - sMn) / sR) * plotH; p.push('<line x1="' + margin.left + '" y1="' + ty + '" x2="' + (margin.left + plotW) + '" y2="' + ty + '" stroke="#e5e7eb" stroke-width="1"/>'); p.push('<text x="' + (margin.left - 8) + '" y="' + (ty + 4) + '" text-anchor="end" font-size="11" fill="#666">' + __chart_formatNum(t) + '</text>'); } var pts = xPos.map(function(x, i) { return x + ',' + yPos[i]; }).join(' '); p.push('<polyline points="' + pts + '" fill="none" stroke="' + clr + '" stroke-width="2" stroke-linejoin="round"/>'); if (showPts) { for (var i = 0; i < xPos.length; i++) { p.push('<circle cx="' + xPos[i] + '" cy="' + yPos[i] + '" r="4" fill="' + clr + '"/>'); } } p.push('<line x1="' + margin.left + '" y1="' + (margin.top + plotH) + '" x2="' + (margin.left + plotW) + '" y2="' + (margin.top + plotH) + '" stroke="#9ca3af" stroke-width="1"/>'); var lStep = Math.max(1, Math.floor(xVals.length / 8)); for (var i = 0; i < xVals.length; i += lStep) { var lx = xPos[i]; var ly = margin.top + plotH + 16; p.push('<text x="' + lx + '" y="' + ly + '" text-anchor="middle" font-size="11" fill="#666">' + __chart_esc(String(xVals[i])) + '</text>'); } p.push('<line x1="' + margin.left + '" y1="' + margin.top + '" x2="' + margin.left + '" y2="' + (margin.top + plotH) + '" stroke="#9ca3af" stroke-width="1"/>'); p.push('</svg>'); return p.join('\\n'); }`,
|
|
1513
|
+
|
|
1514
|
+
scatter_chart: `function scatter_chart(data, opts) { if (!opts) opts = {}; var rows = __chart_getRows(data); var width = opts.width || 600; var height = opts.height || 400; if (rows.length === 0) return __chart_empty(width, height, 'No data'); var xFn = opts.x; var yFn = opts.y; var title = opts.title || ''; var clr = opts.color || __chart_PALETTE[0]; var rad = opts.r || 5; var margin = { top: title ? 50 : 40, right: 20, bottom: 60, left: 70 }; var xVals = rows.map(function(r) { return Number(xFn(r)); }); var yVals = rows.map(function(r) { return Number(yFn(r)); }); var plotW = width - margin.left - margin.right; var plotH = height - margin.top - margin.bottom; var xTk = __chart_niceTicks(Math.min.apply(null, xVals), Math.max.apply(null, xVals)); var yTk = __chart_niceTicks(Math.min.apply(null, yVals), Math.max.apply(null, yVals)); var xMn = xTk[0]; var xMx = xTk[xTk.length - 1]; var yMn = yTk[0]; var yMx = yTk[yTk.length - 1]; var xR = xMx - xMn || 1; var yR = yMx - yMn || 1; var p = []; p.push('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' + width + ' ' + height + '" width="' + width + '" height="' + height + '" style="font-family:system-ui,sans-serif">'); if (title) p.push('<text x="' + (width / 2) + '" y="24" text-anchor="middle" font-size="16" font-weight="bold" fill="#111">' + __chart_esc(title) + '</text>'); for (var i = 0; i < yTk.length; i++) { var t = yTk[i]; var ty = margin.top + plotH - ((t - yMn) / yR) * plotH; p.push('<line x1="' + margin.left + '" y1="' + ty + '" x2="' + (margin.left + plotW) + '" y2="' + ty + '" stroke="#e5e7eb" stroke-width="1"/>'); p.push('<text x="' + (margin.left - 8) + '" y="' + (ty + 4) + '" text-anchor="end" font-size="11" fill="#666">' + __chart_formatNum(t) + '</text>'); } for (var i = 0; i < xTk.length; i++) { var t = xTk[i]; var tx = margin.left + ((t - xMn) / xR) * plotW; p.push('<line x1="' + tx + '" y1="' + margin.top + '" x2="' + tx + '" y2="' + (margin.top + plotH) + '" stroke="#e5e7eb" stroke-width="1"/>'); p.push('<text x="' + tx + '" y="' + (margin.top + plotH + 16) + '" text-anchor="middle" font-size="11" fill="#666">' + __chart_formatNum(t) + '</text>'); } for (var i = 0; i < rows.length; i++) { var cx = margin.left + ((xVals[i] - xMn) / xR) * plotW; var cy = margin.top + plotH - ((yVals[i] - yMn) / yR) * plotH; var cc = Array.isArray(clr) ? clr[i % clr.length] : clr; p.push('<circle cx="' + cx + '" cy="' + cy + '" r="' + rad + '" fill="' + cc + '" opacity="0.7"/>'); } p.push('<line x1="' + margin.left + '" y1="' + (margin.top + plotH) + '" x2="' + (margin.left + plotW) + '" y2="' + (margin.top + plotH) + '" stroke="#9ca3af" stroke-width="1"/>'); p.push('<line x1="' + margin.left + '" y1="' + margin.top + '" x2="' + margin.left + '" y2="' + (margin.top + plotH) + '" stroke="#9ca3af" stroke-width="1"/>'); p.push('</svg>'); return p.join('\\n'); }`,
|
|
1515
|
+
|
|
1516
|
+
histogram: `function histogram(data, opts) { if (!opts) opts = {}; var rows = __chart_getRows(data); var width = opts.width || 600; var height = opts.height || 400; if (rows.length === 0) return __chart_empty(width, height, 'No data'); var colFn = opts.col; var title = opts.title || ''; var clr = opts.color || __chart_PALETTE[0]; var numBins = opts.bins || 20; var margin = { top: title ? 50 : 40, right: 20, bottom: 60, left: 70 }; var values = rows.map(function(r) { return Number(colFn(r)); }).filter(function(v) { return !isNaN(v); }); if (values.length === 0) return __chart_empty(width, height, 'No data'); var dMn = Math.min.apply(null, values); var dMx = Math.max.apply(null, values); var bw = (dMx - dMn) / numBins || 1; var bins = []; for (var i = 0; i < numBins; i++) bins.push({ lo: dMn + i * bw, hi: dMn + (i + 1) * bw, count: 0 }); for (var i = 0; i < values.length; i++) { var idx = Math.floor((values[i] - dMn) / bw); if (idx >= numBins) idx = numBins - 1; if (idx < 0) idx = 0; bins[idx].count++; } var maxC = Math.max.apply(null, bins.map(function(b) { return b.count; })); var ticks = __chart_niceTicks(0, maxC); var scaleMax = ticks[ticks.length - 1]; var plotW = width - margin.left - margin.right; var plotH = height - margin.top - margin.bottom; var barW = plotW / numBins; var p = []; p.push('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' + width + ' ' + height + '" width="' + width + '" height="' + height + '" style="font-family:system-ui,sans-serif">'); if (title) p.push('<text x="' + (width / 2) + '" y="24" text-anchor="middle" font-size="16" font-weight="bold" fill="#111">' + __chart_esc(title) + '</text>'); for (var ti = 0; ti < ticks.length; ti++) { var t = ticks[ti]; var ty = margin.top + plotH - (scaleMax > 0 ? (t / scaleMax) * plotH : 0); p.push('<line x1="' + margin.left + '" y1="' + ty + '" x2="' + (margin.left + plotW) + '" y2="' + ty + '" stroke="#e5e7eb" stroke-width="1"/>'); p.push('<text x="' + (margin.left - 8) + '" y="' + (ty + 4) + '" text-anchor="end" font-size="11" fill="#666">' + __chart_formatNum(t) + '</text>'); } for (var i = 0; i < bins.length; i++) { var barH = scaleMax > 0 ? (bins[i].count / scaleMax) * plotH : 0; var bx = margin.left + i * barW; var by = margin.top + plotH - barH; p.push('<rect x="' + bx + '" y="' + by + '" width="' + barW + '" height="' + barH + '" fill="' + clr + '" stroke="#fff" stroke-width="0.5"/>'); } p.push('<line x1="' + margin.left + '" y1="' + (margin.top + plotH) + '" x2="' + (margin.left + plotW) + '" y2="' + (margin.top + plotH) + '" stroke="#9ca3af" stroke-width="1"/>'); var lc = Math.min(numBins + 1, 8); var ls = Math.max(1, Math.floor(numBins / (lc - 1))); for (var i = 0; i <= numBins; i += ls) { var val = dMn + i * bw; var lx = margin.left + i * barW; var ly = margin.top + plotH + 16; p.push('<text x="' + lx + '" y="' + ly + '" text-anchor="middle" font-size="10" fill="#666">' + __chart_formatNum(val) + '</text>'); } p.push('<line x1="' + margin.left + '" y1="' + margin.top + '" x2="' + margin.left + '" y2="' + (margin.top + plotH) + '" stroke="#9ca3af" stroke-width="1"/>'); p.push('</svg>'); return p.join('\\n'); }`,
|
|
1517
|
+
|
|
1518
|
+
pie_chart: `function pie_chart(data, opts) { if (!opts) opts = {}; var rows = __chart_getRows(data); var width = opts.width || 400; var height = opts.height || 400; if (rows.length === 0) return __chart_empty(width, height, 'No data'); var labelFn = opts.label; var valueFn = opts.value; var title = opts.title || ''; var colors = opts.colors || __chart_PALETTE; var labels = rows.map(function(r) { return String(labelFn(r)); }); var values = rows.map(function(r) { return Number(valueFn(r)); }); var total = values.reduce(function(a, b) { return a + b; }, 0); if (total === 0) return __chart_empty(width, height, 'No data'); var cx = width / 2; var cy = title ? (height + 30) / 2 : height / 2; var r = Math.min(cx, cy) - 50; var p = []; p.push('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' + width + ' ' + height + '" width="' + width + '" height="' + height + '" style="font-family:system-ui,sans-serif">'); if (title) p.push('<text x="' + (width / 2) + '" y="24" text-anchor="middle" font-size="16" font-weight="bold" fill="#111">' + __chart_esc(title) + '</text>'); var sa = -Math.PI / 2; for (var i = 0; i < values.length; i++) { var sl = (values[i] / total) * 2 * Math.PI; var ea = sa + sl; var x1 = cx + r * Math.cos(sa); var y1 = cy + r * Math.sin(sa); var x2 = cx + r * Math.cos(ea); var y2 = cy + r * Math.sin(ea); var la = sl > Math.PI ? 1 : 0; var c = colors[i % colors.length]; if (values.length === 1) { p.push('<circle cx="' + cx + '" cy="' + cy + '" r="' + r + '" fill="' + c + '"/>'); } else { p.push('<path d="M ' + cx + ' ' + cy + ' L ' + x1 + ' ' + y1 + ' A ' + r + ' ' + r + ' 0 ' + la + ' 1 ' + x2 + ' ' + y2 + ' Z" fill="' + c + '" stroke="#fff" stroke-width="1.5"/>'); } var ma = sa + sl / 2; var lr = r * 0.7; var lx = cx + lr * Math.cos(ma); var ly = cy + lr * Math.sin(ma); var pct = ((values[i] / total) * 100).toFixed(1); p.push('<text x="' + lx + '" y="' + ly + '" text-anchor="middle" font-size="11" fill="#fff" font-weight="bold">' + __chart_esc(labels[i]) + '</text>'); p.push('<text x="' + lx + '" y="' + (ly + 13) + '" text-anchor="middle" font-size="10" fill="#fff">' + pct + '%</text>'); sa = ea; } p.push('</svg>'); return p.join('\\n'); }`,
|
|
1519
|
+
|
|
1520
|
+
// ── Parquet Read/Write ────────────────────────────────────────
|
|
1521
|
+
readParquet: `async function readParquet(path) {
|
|
1522
|
+
var fs = await import('fs'); var arrow = await import('apache-arrow'); var pw = await import('parquet-wasm/node');
|
|
1523
|
+
var fileBytes = new Uint8Array(fs.readFileSync(path));
|
|
1524
|
+
var wasmTable = pw.readParquet(fileBytes);
|
|
1525
|
+
var ipcBytes = wasmTable.intoIPCStream();
|
|
1526
|
+
var arrowTable = arrow.tableFromIPC(ipcBytes);
|
|
1527
|
+
var columns = arrowTable.schema.fields.map(function(f) { return f.name; });
|
|
1528
|
+
var rows = [];
|
|
1529
|
+
for (var i = 0; i < arrowTable.numRows; i++) {
|
|
1530
|
+
var row = {};
|
|
1531
|
+
for (var ci = 0; ci < columns.length; ci++) { var col = columns[ci]; var val = arrowTable.getChild(col).get(i); row[col] = val === undefined ? null : val; }
|
|
1532
|
+
rows.push(row);
|
|
1533
|
+
}
|
|
1534
|
+
return Table(rows, columns);
|
|
1535
|
+
}`,
|
|
1536
|
+
|
|
1537
|
+
writeParquet: `async function writeParquet(tableData, path, opts) {
|
|
1538
|
+
var fs = await import('fs'); var arrow = await import('apache-arrow'); var pw = await import('parquet-wasm/node');
|
|
1539
|
+
var t = tableData && tableData._rows ? tableData : Table(Array.isArray(tableData) ? tableData : []);
|
|
1540
|
+
var columns = t._columns;
|
|
1541
|
+
var COMP_MAP = { snappy: 1, gzip: 2, brotli: 3, zstd: 5, lz4: 6, uncompressed: 0, none: 0 };
|
|
1542
|
+
function _inferType(values) { for (var i = 0; i < values.length; i++) { var v = values[i]; if (v === null || v === undefined) continue; if (typeof v === 'boolean') return 'bool'; if (typeof v === 'number') return Number.isInteger(v) ? 'int' : 'float'; if (typeof v === 'string') return 'string'; } return 'string'; }
|
|
1543
|
+
var colVecs = {};
|
|
1544
|
+
for (var ci = 0; ci < columns.length; ci++) {
|
|
1545
|
+
var col = columns[ci]; var values = t._rows.map(function(r) { var v = r[col]; return v === undefined ? null : v; });
|
|
1546
|
+
var tp = _inferType(values);
|
|
1547
|
+
if (tp === 'int') colVecs[col] = arrow.vectorFromArray(values, new arrow.Int32());
|
|
1548
|
+
else if (tp === 'float') colVecs[col] = arrow.vectorFromArray(values, new arrow.Float64());
|
|
1549
|
+
else if (tp === 'bool') colVecs[col] = arrow.vectorFromArray(values, new arrow.Bool());
|
|
1550
|
+
else colVecs[col] = arrow.vectorFromArray(values, new arrow.Utf8());
|
|
1551
|
+
}
|
|
1552
|
+
var arrowTable = new arrow.Table(colVecs);
|
|
1553
|
+
var ipcBytes = arrow.tableToIPC(arrowTable, 'stream');
|
|
1554
|
+
var wasmTable = pw.Table.fromIPCStream(ipcBytes);
|
|
1555
|
+
var writerProps = null;
|
|
1556
|
+
var comp = (opts && opts.compression) || 'snappy';
|
|
1557
|
+
var compCode = COMP_MAP[comp.toLowerCase()];
|
|
1558
|
+
if (compCode !== undefined) { writerProps = new pw.WriterPropertiesBuilder().setCompression(compCode).build(); }
|
|
1559
|
+
var parquetBytes = pw.writeParquet(wasmTable, writerProps);
|
|
1560
|
+
fs.writeFileSync(path, parquetBytes);
|
|
1561
|
+
}`,
|
|
1562
|
+
|
|
1563
|
+
readExcel: `async function readExcel(path, opts) {
|
|
1564
|
+
var ExcelJS = require('exceljs');
|
|
1565
|
+
var workbook = new ExcelJS.Workbook();
|
|
1566
|
+
await workbook.xlsx.readFile(path);
|
|
1567
|
+
var worksheet;
|
|
1568
|
+
if (opts && typeof opts.sheet === 'string') { worksheet = workbook.getWorksheet(opts.sheet); if (!worksheet) throw new Error('Sheet "' + opts.sheet + '" not found'); }
|
|
1569
|
+
else if (opts && typeof opts.sheet === 'number') { var sheets = workbook.worksheets; if (opts.sheet < 1 || opts.sheet > sheets.length) throw new Error('Sheet index out of range'); worksheet = sheets[opts.sheet - 1]; }
|
|
1570
|
+
else { worksheet = workbook.worksheets[0]; }
|
|
1571
|
+
if (!worksheet) throw new Error('No worksheets found');
|
|
1572
|
+
var headerRow = worksheet.getRow(1);
|
|
1573
|
+
var colArr = [];
|
|
1574
|
+
headerRow.eachCell({ includeEmpty: false }, function(cell, colNumber) { colArr[colNumber] = __excelCellValue(cell); });
|
|
1575
|
+
var colMap = [];
|
|
1576
|
+
for (var i = 1; i < colArr.length; i++) { if (colArr[i] !== undefined && colArr[i] !== null) colMap.push({ colNumber: i, name: String(colArr[i]) }); }
|
|
1577
|
+
if (colMap.length === 0) return Table([], []);
|
|
1578
|
+
var columnNames = colMap.map(function(c) { return c.name; });
|
|
1579
|
+
var rows = [];
|
|
1580
|
+
var rowCount = worksheet.rowCount;
|
|
1581
|
+
for (var r = 2; r <= rowCount; r++) {
|
|
1582
|
+
var excelRow = worksheet.getRow(r);
|
|
1583
|
+
var row = {};
|
|
1584
|
+
for (var ci = 0; ci < colMap.length; ci++) { var cm = colMap[ci]; var cell = excelRow.getCell(cm.colNumber); row[cm.name] = __excelCellValue(cell); }
|
|
1585
|
+
rows.push(row);
|
|
1586
|
+
}
|
|
1587
|
+
return Table(rows, columnNames);
|
|
1588
|
+
}`,
|
|
1589
|
+
|
|
1590
|
+
writeExcel: `async function writeExcel(tableData, path, opts) {
|
|
1591
|
+
var ExcelJS = require('exceljs');
|
|
1592
|
+
var t = tableData && tableData._rows ? tableData : Table(Array.isArray(tableData) ? tableData : []);
|
|
1593
|
+
var workbook = new ExcelJS.Workbook();
|
|
1594
|
+
var sheetName = (opts && opts.sheet) || 'Sheet1';
|
|
1595
|
+
var worksheet = workbook.addWorksheet(sheetName);
|
|
1596
|
+
var cols = t._columns;
|
|
1597
|
+
if (cols.length > 0) worksheet.addRow(cols);
|
|
1598
|
+
for (var i = 0; i < t._rows.length; i++) {
|
|
1599
|
+
var row = t._rows[i];
|
|
1600
|
+
var values = [];
|
|
1601
|
+
for (var ci = 0; ci < cols.length; ci++) { var v = row[cols[ci]]; values.push(v === undefined ? null : v); }
|
|
1602
|
+
worksheet.addRow(values);
|
|
1603
|
+
}
|
|
1604
|
+
await workbook.xlsx.writeFile(path);
|
|
1605
|
+
}`,
|
|
1606
|
+
|
|
1607
|
+
__excelCellValue: `function __excelCellValue(cell) {
|
|
1608
|
+
if (!cell || cell.type === 0) return null;
|
|
1609
|
+
var val = cell.value;
|
|
1610
|
+
if (val === null || val === undefined) return null;
|
|
1611
|
+
if (typeof val === 'object' && val.formula !== undefined) { var result = val.result; return (result === null || result === undefined) ? null : result; }
|
|
1612
|
+
if (typeof val === 'object' && val.richText) { return val.richText.map(function(p) { return p.text; }).join(''); }
|
|
1613
|
+
if (typeof val === 'object' && val.hyperlink) { return val.text || val.hyperlink; }
|
|
1614
|
+
if (typeof val === 'object' && val.error) { return null; }
|
|
1615
|
+
return val;
|
|
1616
|
+
}`,
|
|
1617
|
+
|
|
1618
|
+
heatmap: `function heatmap(data, opts) { if (!opts) opts = {}; var rows = __chart_getRows(data); var width = opts.width || 600; var height = opts.height || 400; if (rows.length === 0) return __chart_empty(width, height, 'No data'); var xFn = opts.x; var yFn = opts.y; var valueFn = opts.value; var title = opts.title || ''; var margin = { top: title ? 50 : 40, right: 40, bottom: 60, left: 80 }; var xCats = []; var yCats = []; var xSet = new Set(); var ySet = new Set(); for (var i = 0; i < rows.length; i++) { var xv = String(xFn(rows[i])); var yv = String(yFn(rows[i])); if (!xSet.has(xv)) { xSet.add(xv); xCats.push(xv); } if (!ySet.has(yv)) { ySet.add(yv); yCats.push(yv); } } var grid = {}; var vMn = Infinity; var vMx = -Infinity; for (var i = 0; i < rows.length; i++) { var xv = String(xFn(rows[i])); var yv = String(yFn(rows[i])); var val = Number(valueFn(rows[i])); grid[xv + '|' + yv] = val; if (val < vMn) vMn = val; if (val > vMx) vMx = val; } var vR = vMx - vMn || 1; var plotW = width - margin.left - margin.right; var plotH = height - margin.top - margin.bottom; var cellW = plotW / xCats.length; var cellH = plotH / yCats.length; function hc(val) { var t = (val - vMn) / vR; var r = Math.round(255 - t * (255 - 79)); var g = Math.round(255 - t * (255 - 70)); var b = Math.round(255 - t * (255 - 229)); return 'rgb(' + r + ',' + g + ',' + b + ')'; } var p = []; p.push('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' + width + ' ' + height + '" width="' + width + '" height="' + height + '" style="font-family:system-ui,sans-serif">'); if (title) p.push('<text x="' + (width / 2) + '" y="24" text-anchor="middle" font-size="16" font-weight="bold" fill="#111">' + __chart_esc(title) + '</text>'); for (var xi = 0; xi < xCats.length; xi++) { for (var yi = 0; yi < yCats.length; yi++) { var key = xCats[xi] + '|' + yCats[yi]; var val = grid[key]; var rx = margin.left + xi * cellW; var ry = margin.top + yi * cellH; var fill = val !== undefined ? hc(val) : '#f3f4f6'; p.push('<rect x="' + rx + '" y="' + ry + '" width="' + cellW + '" height="' + cellH + '" fill="' + fill + '" stroke="#fff" stroke-width="1"/>'); if (val !== undefined) { var tc = ((val - vMn) / vR) > 0.5 ? '#fff' : '#111'; p.push('<text x="' + (rx + cellW / 2) + '" y="' + (ry + cellH / 2 + 4) + '" text-anchor="middle" font-size="11" fill="' + tc + '">' + __chart_formatNum(val) + '</text>'); } } } for (var xi = 0; xi < xCats.length; xi++) { var lx = margin.left + xi * cellW + cellW / 2; var ly = margin.top + plotH + 16; p.push('<text x="' + lx + '" y="' + ly + '" text-anchor="middle" font-size="11" fill="#666">' + __chart_esc(xCats[xi]) + '</text>'); } for (var yi = 0; yi < yCats.length; yi++) { var lx = margin.left - 8; var ly = margin.top + yi * cellH + cellH / 2 + 4; p.push('<text x="' + lx + '" y="' + ly + '" text-anchor="end" font-size="11" fill="#666">' + __chart_esc(yCats[yi]) + '</text>'); } p.push('</svg>'); return p.join('\\n'); }`,
|
|
1293
1619
|
};
|
|
1294
1620
|
|
|
1295
1621
|
// All known builtin names for matching
|
|
@@ -1309,10 +1635,12 @@ export const STDLIB_DEPS = {
|
|
|
1309
1635
|
// These are provided by RESULT_OPTION, not the builtin map, so no dep here
|
|
1310
1636
|
// Namespace modules that use builtins internally
|
|
1311
1637
|
json: ['Ok', 'Err'],
|
|
1638
|
+
crypto: ['Ok', 'Err'],
|
|
1312
1639
|
re: ['Ok', 'Err'],
|
|
1313
1640
|
dt: ['Ok', 'Err'],
|
|
1314
1641
|
fs: ['Ok', 'Err'],
|
|
1315
1642
|
url: ['Ok', 'Err'],
|
|
1643
|
+
http: ['Ok', 'Err'],
|
|
1316
1644
|
parse_url: ['Ok', 'Err'],
|
|
1317
1645
|
regex_test: ['__regex_cache'],
|
|
1318
1646
|
regex_match: ['Ok', 'Err', '__regex_cache'],
|
|
@@ -1331,6 +1659,8 @@ export const STDLIB_DEPS = {
|
|
|
1331
1659
|
LazyTable: ['Table', 'table_where', 'table_group_by'],
|
|
1332
1660
|
// Seq uses Some/None
|
|
1333
1661
|
Seq: ['Some', 'None'],
|
|
1662
|
+
// Channel uses Some/None
|
|
1663
|
+
Channel: ['Some', 'None'],
|
|
1334
1664
|
// compare family
|
|
1335
1665
|
compare: ['Less', 'Equal', 'Greater'],
|
|
1336
1666
|
compare_by: ['Less', 'Equal', 'Greater'],
|
|
@@ -1344,6 +1674,31 @@ export const STDLIB_DEPS = {
|
|
|
1344
1674
|
cyan: ['color'],
|
|
1345
1675
|
magenta: ['color'],
|
|
1346
1676
|
gray: ['color'],
|
|
1677
|
+
// LRU cache namespace
|
|
1678
|
+
LRUCache: ['Some', 'None'],
|
|
1679
|
+
cache: ['LRUCache', 'Some', 'None'],
|
|
1680
|
+
// Window functions require Table
|
|
1681
|
+
table_window: ['Table'],
|
|
1682
|
+
// Sampling functions
|
|
1683
|
+
table_sample: ['Table', '__xorshift128'],
|
|
1684
|
+
table_stratified_sample: ['Table', 'table_sample', '__xorshift128'],
|
|
1685
|
+
// SQLite connector
|
|
1686
|
+
sqlite: ['Table'],
|
|
1687
|
+
// Parquet read/write
|
|
1688
|
+
readParquet: ['Table'],
|
|
1689
|
+
writeParquet: ['Table'],
|
|
1690
|
+
readExcel: ['Table', '__excelCellValue'],
|
|
1691
|
+
writeExcel: ['Table'],
|
|
1692
|
+
read: ['Table', '__parseCSV', '__parseJSONL', 'readParquet', 'readExcel', '__excelCellValue'],
|
|
1693
|
+
write: ['Table', 'writeParquet', 'writeExcel'],
|
|
1694
|
+
// SVG Charting
|
|
1695
|
+
__chart_helpers: ['Table'],
|
|
1696
|
+
bar_chart: ['Table', '__chart_helpers'],
|
|
1697
|
+
line_chart: ['Table', '__chart_helpers'],
|
|
1698
|
+
scatter_chart: ['Table', '__chart_helpers'],
|
|
1699
|
+
histogram: ['Table', '__chart_helpers'],
|
|
1700
|
+
pie_chart: ['Table', '__chart_helpers'],
|
|
1701
|
+
heatmap: ['Table', '__chart_helpers'],
|
|
1347
1702
|
};
|
|
1348
1703
|
|
|
1349
1704
|
// Resolve all transitive dependencies for a set of used names
|