@ggterm/core 0.3.1 → 0.3.2

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/dist/cli-plot.js CHANGED
@@ -14602,7 +14602,6 @@ __export(exports_serve, {
14602
14602
  import { watch, writeFileSync as writeFileSync3, unlinkSync } from "fs";
14603
14603
  import { join as join3 } from "path";
14604
14604
  import { createServer } from "http";
14605
- import { createHash } from "crypto";
14606
14605
  import { spawn } from "child_process";
14607
14606
  function plotToVegaLite(plot) {
14608
14607
  const geomTypes = plot._provenance.geomTypes;
@@ -14620,27 +14619,6 @@ function getLatestPayload() {
14620
14619
  const { spec, provenance } = plotToVegaLite(plot);
14621
14620
  return JSON.stringify({ type: "plot", spec, provenance });
14622
14621
  }
14623
- function encodeWebSocketFrame(data) {
14624
- const payload = Buffer.from(data, "utf-8");
14625
- const len = payload.length;
14626
- let header;
14627
- if (len < 126) {
14628
- header = Buffer.alloc(2);
14629
- header[0] = 129;
14630
- header[1] = len;
14631
- } else if (len < 65536) {
14632
- header = Buffer.alloc(4);
14633
- header[0] = 129;
14634
- header[1] = 126;
14635
- header.writeUInt16BE(len, 2);
14636
- } else {
14637
- header = Buffer.alloc(10);
14638
- header[0] = 129;
14639
- header[1] = 127;
14640
- header.writeBigUInt64BE(BigInt(len), 2);
14641
- }
14642
- return Buffer.concat([header, payload]);
14643
- }
14644
14622
  function jsonResponse(res, data, status = 200) {
14645
14623
  const body = JSON.stringify(data);
14646
14624
  res.writeHead(status, { "content-type": "application/json" });
@@ -14661,10 +14639,12 @@ function handleServe(port) {
14661
14639
  const payload = getLatestPayload();
14662
14640
  if (!payload)
14663
14641
  return;
14664
- const frame = encodeWebSocketFrame(payload);
14642
+ const sseData = `data: ${payload}
14643
+
14644
+ `;
14665
14645
  for (const client of clients) {
14666
14646
  try {
14667
- client.write(frame);
14647
+ client.write(sseData);
14668
14648
  } catch {
14669
14649
  clients.delete(client);
14670
14650
  }
@@ -14673,6 +14653,21 @@ function handleServe(port) {
14673
14653
  });
14674
14654
  const server = createServer((req, res) => {
14675
14655
  const url = new URL(req.url || "/", `http://localhost:${p}`);
14656
+ if (url.pathname === "/events") {
14657
+ res.writeHead(200, {
14658
+ "content-type": "text/event-stream",
14659
+ "cache-control": "no-cache",
14660
+ connection: "keep-alive"
14661
+ });
14662
+ clients.add(res);
14663
+ const payload = getLatestPayload();
14664
+ if (payload)
14665
+ res.write(`data: ${payload}
14666
+
14667
+ `);
14668
+ req.on("close", () => clients.delete(res));
14669
+ return;
14670
+ }
14676
14671
  if (url.pathname === "/api/latest") {
14677
14672
  const payload = getLatestPayload();
14678
14673
  if (!payload)
@@ -14698,54 +14693,6 @@ function handleServe(port) {
14698
14693
  res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
14699
14694
  res.end(CLIENT_HTML);
14700
14695
  });
14701
- server.on("upgrade", (req, socket, _head) => {
14702
- const url = new URL(req.url || "/", `http://localhost:${p}`);
14703
- if (url.pathname !== "/ws") {
14704
- socket.destroy();
14705
- return;
14706
- }
14707
- const key = req.headers["sec-websocket-key"];
14708
- if (!key) {
14709
- socket.destroy();
14710
- return;
14711
- }
14712
- const accept = createHash("sha1").update(key + "258EAFA5-E914-47DA-95CA-5AB5DC85B7A8").digest("base64");
14713
- socket.write(`HTTP/1.1 101 Switching Protocols\r
14714
- ` + `Upgrade: websocket\r
14715
- ` + `Connection: Upgrade\r
14716
- ` + `Sec-WebSocket-Accept: ${accept}\r
14717
- ` + `\r
14718
- `);
14719
- clients.add(socket);
14720
- const payload = getLatestPayload();
14721
- if (payload)
14722
- socket.write(encodeWebSocketFrame(payload));
14723
- socket.on("close", () => clients.delete(socket));
14724
- socket.on("error", () => clients.delete(socket));
14725
- socket.on("data", (data) => {
14726
- if (data.length < 2)
14727
- return;
14728
- const opcode = data[0] & 15;
14729
- if (opcode === 8) {
14730
- const closeFrame = Buffer.alloc(2);
14731
- closeFrame[0] = 136;
14732
- closeFrame[1] = 0;
14733
- try {
14734
- socket.write(closeFrame);
14735
- } catch {}
14736
- socket.end();
14737
- clients.delete(socket);
14738
- return;
14739
- }
14740
- if (opcode === 9) {
14741
- const pong = Buffer.from(data);
14742
- pong[0] = pong[0] & 240 | 10;
14743
- try {
14744
- socket.write(pong);
14745
- } catch {}
14746
- }
14747
- });
14748
- });
14749
14696
  server.listen(p, () => {
14750
14697
  const url = `http://localhost:${p}`;
14751
14698
  console.log(`ggterm live viewer running at ${url}`);
@@ -15034,7 +14981,6 @@ let history = [];
15034
14981
  let historyIndex = {};
15035
14982
  let currentIdx = -1;
15036
14983
  let view = null;
15037
- let ws = null;
15038
14984
 
15039
14985
  function updateMeta(prov) {
15040
14986
  if (!prov) return;
@@ -15192,17 +15138,12 @@ function downloadPNG() {
15192
15138
  }
15193
15139
 
15194
15140
  function connect() {
15195
- const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
15196
- ws = new WebSocket(proto + '//' + location.host + '/ws');
15141
+ const es = new EventSource('/events');
15197
15142
 
15198
- ws.onopen = () => { statusEl.classList.add('connected'); };
15199
- ws.onclose = () => {
15200
- statusEl.classList.remove('connected');
15201
- setTimeout(connect, 2000);
15202
- };
15203
- ws.onerror = () => ws.close();
15143
+ es.onopen = () => { statusEl.classList.add('connected'); };
15144
+ es.onerror = () => { statusEl.classList.remove('connected'); };
15204
15145
 
15205
- ws.onmessage = (e) => {
15146
+ es.onmessage = (e) => {
15206
15147
  const data = JSON.parse(e.data);
15207
15148
  if (data.type === 'plot') {
15208
15149
  history.push(data);
@@ -16389,19 +16330,68 @@ Examples:`);
16389
16330
  Tip: Use "inspect <file>" to see available columns`);
16390
16331
  process.exit(1);
16391
16332
  }
16392
- if (!args[0].includes(".") && !fileExists(args[0])) {
16333
+ const BUILTIN_DATASETS = {
16334
+ iris: () => {
16335
+ const species = ["setosa", "versicolor", "virginica"];
16336
+ const data2 = Array.from({ length: 150 }, (_, i) => {
16337
+ const sp = species[Math.floor(i / 50)];
16338
+ const base = sp === "setosa" ? 0 : sp === "versicolor" ? 1 : 2;
16339
+ return {
16340
+ sepal_length: +(5 + base * 0.5 + Math.random()).toFixed(1),
16341
+ sepal_width: +(3 + Math.random() * 0.5).toFixed(1),
16342
+ petal_length: +(1.5 + base * 2 + Math.random()).toFixed(1),
16343
+ petal_width: +(0.2 + base * 0.8 + Math.random() * 0.3).toFixed(1),
16344
+ species: sp
16345
+ };
16346
+ });
16347
+ return { headers: ["sepal_length", "sepal_width", "petal_length", "petal_width", "species"], data: data2 };
16348
+ },
16349
+ mtcars: () => {
16350
+ const data2 = [
16351
+ { name: "Mazda RX4", mpg: 21, cyl: 6, hp: 110, wt: 2.62 },
16352
+ { name: "Mazda RX4 Wag", mpg: 21, cyl: 6, hp: 110, wt: 2.875 },
16353
+ { name: "Datsun 710", mpg: 22.8, cyl: 4, hp: 93, wt: 2.32 },
16354
+ { name: "Hornet 4 Drive", mpg: 21.4, cyl: 6, hp: 110, wt: 3.215 },
16355
+ { name: "Hornet Sportabout", mpg: 18.7, cyl: 8, hp: 175, wt: 3.44 },
16356
+ { name: "Valiant", mpg: 18.1, cyl: 6, hp: 105, wt: 3.46 },
16357
+ { name: "Duster 360", mpg: 14.3, cyl: 8, hp: 245, wt: 3.57 },
16358
+ { name: "Merc 240D", mpg: 24.4, cyl: 4, hp: 62, wt: 3.19 },
16359
+ { name: "Merc 230", mpg: 22.8, cyl: 4, hp: 95, wt: 3.15 },
16360
+ { name: "Merc 280", mpg: 19.2, cyl: 6, hp: 123, wt: 3.44 },
16361
+ { name: "Merc 280C", mpg: 17.8, cyl: 6, hp: 123, wt: 3.44 },
16362
+ { name: "Merc 450SE", mpg: 16.4, cyl: 8, hp: 180, wt: 4.07 },
16363
+ { name: "Merc 450SL", mpg: 17.3, cyl: 8, hp: 180, wt: 3.73 },
16364
+ { name: "Merc 450SLC", mpg: 15.2, cyl: 8, hp: 180, wt: 3.78 },
16365
+ { name: "Cadillac Fleetwood", mpg: 10.4, cyl: 8, hp: 205, wt: 5.25 },
16366
+ { name: "Lincoln Continental", mpg: 10.4, cyl: 8, hp: 215, wt: 5.424 }
16367
+ ];
16368
+ return { headers: ["name", "mpg", "cyl", "hp", "wt"], data: data2 };
16369
+ }
16370
+ };
16371
+ const [dataFile, x, y, color, title, geomSpec = "point", facetVar] = args;
16372
+ let headers;
16373
+ let data;
16374
+ if (BUILTIN_DATASETS[dataFile]) {
16375
+ const result = BUILTIN_DATASETS[dataFile]();
16376
+ headers = result.headers;
16377
+ data = result.data;
16378
+ } else if (!args[0].includes(".") && !fileExists(args[0])) {
16393
16379
  console.error(`
16394
16380
  Error: "${args[0]}" doesn't look like a file path`);
16395
16381
  console.error(`
16382
+ Built-in datasets: iris, mtcars`);
16383
+ console.error(`
16396
16384
  Did you mean one of these commands?`);
16397
16385
  console.error(` inspect <file> - Show column types`);
16398
16386
  console.error(` suggest <file> - Get plot suggestions`);
16399
16387
  console.error(` history - List saved plots`);
16400
16388
  console.error(` help - Show full usage`);
16401
16389
  process.exit(1);
16390
+ } else {
16391
+ const loaded = loadData(dataFile);
16392
+ headers = loaded.headers;
16393
+ data = loaded.data;
16402
16394
  }
16403
- const [dataFile, x, y, color, title, geomSpec = "point", facetVar] = args;
16404
- let { headers, data } = loadData(dataFile);
16405
16395
  const { baseGeom: geomType, refLines } = parseGeomSpec(geomSpec);
16406
16396
  if (geomType === "manhattan" && y && y !== "-") {
16407
16397
  data = data.map((row) => {
@@ -1 +1 @@
1
- {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA6gBH,wBAAgB,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CA2I/C"}
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA0eH,wBAAgB,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAmG/C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ggterm/core",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Grammar of Graphics engine for terminals",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",