parquetlens 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -0
- package/dist/chunk-2RGMZZ7F.js +123 -0
- package/dist/chunk-2RGMZZ7F.js.map +1 -0
- package/dist/chunk-3N45GGD2.js +113 -0
- package/dist/chunk-3N45GGD2.js.map +1 -0
- package/dist/chunk-AYPIRAOL.js +112 -0
- package/dist/chunk-AYPIRAOL.js.map +1 -0
- package/dist/chunk-IMVXDI4K.js +112 -0
- package/dist/chunk-IMVXDI4K.js.map +1 -0
- package/dist/chunk-NRRDNC7S.js +485 -0
- package/dist/chunk-NRRDNC7S.js.map +1 -0
- package/dist/main.js +16 -6
- package/dist/main.js.map +1 -1
- package/dist/tui.js +87 -16
- package/dist/tui.js.map +1 -1
- package/package.json +6 -4
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/main.ts"],"sourcesContent":["#!/usr/bin/env node\nimport {\n ParquetReadOptions,\n readParquetTableFromPath,\n readParquetTableFromStdin,\n} from \"@parquetlens/parquet-reader\";\nimport type { Table } from \"apache-arrow\";\nimport { spawnSync } from \"node:child_process\";\nimport path from \"node:path\";\n\ntype TuiMode = \"auto\" | \"on\" | \"off\";\n\ntype Options = {\n limit: number;\n columns: string[];\n json: boolean;\n schemaOnly: boolean;\n showSchema: boolean;\n tuiMode: TuiMode;\n};\n\ntype ParsedArgs = {\n input?: string;\n options: Options;\n limitSpecified: boolean;\n help: boolean;\n error?: string;\n};\n\nconst DEFAULT_LIMIT = 20;\n\nfunction parseArgs(argv: string[]): ParsedArgs {\n const options: Options = {\n limit: DEFAULT_LIMIT,\n columns: [],\n json: false,\n schemaOnly: false,\n showSchema: true,\n tuiMode: \"auto\",\n };\n\n let input: string | undefined;\n let limitSpecified = false;\n\n for (let i = 0; i < argv.length; i += 1) {\n const arg = argv[i];\n\n if (arg === \"--\") {\n continue;\n }\n\n if (arg === \"-h\" || arg === \"--help\") {\n return { options, limitSpecified, help: true };\n }\n\n if (arg === \"--json\") {\n options.json = true;\n options.tuiMode = \"off\";\n continue;\n }\n\n if (arg === \"--tui\") {\n options.tuiMode = \"on\";\n continue;\n }\n\n if (arg === \"--plain\" || arg === \"--no-tui\") {\n options.tuiMode = \"off\";\n continue;\n }\n\n if (arg === \"--schema\") {\n options.schemaOnly = true;\n options.tuiMode = \"off\";\n continue;\n }\n\n if (arg === \"--no-schema\") {\n options.showSchema = false;\n continue;\n }\n\n const limitValue = readOptionValue(arg, \"--limit\", argv[i + 1]);\n if (limitValue) {\n const parsed = Number.parseInt(limitValue.value, 10);\n if (!Number.isFinite(parsed) || parsed < 0) {\n return {\n options,\n limitSpecified,\n help: false,\n error: `invalid --limit value: ${limitValue.value}`,\n };\n }\n options.limit = parsed;\n limitSpecified = true;\n if (limitValue.usedNext) {\n i += 1;\n }\n continue;\n }\n\n const columnsValue = readOptionValue(arg, \"--columns\", argv[i + 1]);\n if (columnsValue) {\n const rawColumns = columnsValue.value\n .split(\",\")\n .map((value) => value.trim())\n .filter(Boolean);\n options.columns = rawColumns;\n if (columnsValue.usedNext) {\n i += 1;\n }\n continue;\n }\n\n if (arg === \"-\") {\n if (input) {\n return { options, limitSpecified, help: false, error: \"unexpected extra argument: -\" };\n }\n input = arg;\n continue;\n }\n\n if (arg.startsWith(\"-\")) {\n return { options, limitSpecified, help: false, error: `unknown option: ${arg}` };\n }\n\n if (input) {\n return { options, limitSpecified, help: false, error: `unexpected extra argument: ${arg}` };\n }\n\n input = arg;\n }\n\n return { input, options, limitSpecified, help: false };\n}\n\nfunction readOptionValue(\n arg: string,\n name: \"--limit\" | \"--columns\",\n next?: string,\n): { value: string; usedNext: boolean } | null {\n if (arg === name) {\n if (!next || next.startsWith(\"-\")) {\n return null;\n }\n return { value: next, usedNext: true };\n }\n\n if (arg.startsWith(`${name}=`)) {\n return { value: arg.slice(name.length + 1), usedNext: false };\n }\n\n return null;\n}\n\nfunction printUsage(): void {\n const helpText = `parquetlens <file|-> [options]\n\noptions:\n --limit, --limit=<n> number of rows to show (default: ${DEFAULT_LIMIT})\n --columns, --columns=<c> comma-separated column list\n --schema print schema only\n --no-schema skip schema output\n --json output rows as json lines\n --tui open interactive viewer (default)\n --plain, --no-tui disable interactive viewer\n -h, --help show help\n\nexamples:\n parquetlens data.parquet --limit 25\n parquetlens data.parquet --columns=city,state\n parquetlens data.parquet --tui\n parquetlens data.parquet --plain\n parquetlens - < input.parquet\n`;\n\n process.stdout.write(helpText);\n}\n\nfunction formatSchema(table: Table): string {\n const lines = table.schema.fields.map((field, index) => {\n const typeName = String(field.type);\n return `${index + 1}. ${field.name}: ${typeName}`;\n });\n\n return lines.join(\"\\n\");\n}\n\nfunction totalRows(table: Table): number {\n return table.batches.reduce((count, batch) => count + batch.numRows, 0);\n}\n\nfunction resolveColumns(table: Table, requested: string[]): { names: string[]; indices: number[] } {\n const fields = table.schema.fields;\n const nameToIndex = new Map<string, number>();\n\n fields.forEach((field, index) => {\n nameToIndex.set(field.name, index);\n });\n\n const names = requested.length > 0 ? requested : fields.map((field) => field.name);\n const missing = names.filter((name) => !nameToIndex.has(name));\n\n if (missing.length > 0) {\n throw new Error(`unknown columns: ${missing.join(\", \")}`);\n }\n\n return {\n names,\n indices: names.map((name) => nameToIndex.get(name) ?? -1),\n };\n}\n\nfunction formatCell(value: unknown): unknown {\n if (value === null || value === undefined) {\n return null;\n }\n\n if (typeof value === \"bigint\") {\n return value.toString();\n }\n\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (value instanceof Uint8Array) {\n return `Uint8Array(${value.length})`;\n }\n\n if (typeof value === \"object\") {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n }\n\n return value;\n}\n\nfunction previewRows(\n table: Table,\n limit: number,\n requestedColumns: string[],\n): Record<string, unknown>[] {\n const { names, indices } = resolveColumns(table, requestedColumns);\n const rows: Record<string, unknown>[] = [];\n\n for (const batch of table.batches) {\n const vectors = indices.map((index) => batch.getChildAt(index));\n\n for (let rowIndex = 0; rowIndex < batch.numRows; rowIndex += 1) {\n if (rows.length >= limit) {\n return rows;\n }\n\n const row: Record<string, unknown> = {};\n\n for (let colIndex = 0; colIndex < names.length; colIndex += 1) {\n const vector = vectors[colIndex];\n row[names[colIndex]] = formatCell(vector?.get(rowIndex));\n }\n\n rows.push(row);\n }\n }\n\n return rows;\n}\n\nasync function loadTable(\n input: string | undefined,\n readOptions: ParquetReadOptions,\n): Promise<Table> {\n const stdinFallback = process.stdin.isTTY ? undefined : \"-\";\n const source = input ?? stdinFallback;\n\n if (!source) {\n throw new Error(\"missing input file (pass a path or pipe stdin)\");\n }\n\n if (source === \"-\") {\n return readParquetTableFromStdin(\"stdin.parquet\", readOptions);\n }\n\n return readParquetTableFromPath(source, readOptions);\n}\n\nasync function main(): Promise<void> {\n const { input, options, limitSpecified, help, error } = parseArgs(process.argv.slice(2));\n\n if (help) {\n printUsage();\n return;\n }\n\n if (error) {\n process.stderr.write(`parquetlens: ${error}\\n`);\n printUsage();\n process.exitCode = 1;\n return;\n }\n\n const wantsTui = resolveTuiMode(options.tuiMode, options);\n if (wantsTui) {\n if (!input || input === \"-\") {\n process.stderr.write(\"parquetlens: tui mode requires a file path (stdin not supported)\\n\");\n process.exitCode = 1;\n return;\n }\n\n if (!process.stdin.isTTY || !process.stdout.isTTY) {\n process.stderr.write(\"parquetlens: tui mode requires a tty, falling back to plain output\\n\");\n } else if (!isBunRuntime()) {\n const spawned = spawnBun(process.argv.slice(1));\n if (spawned) {\n return;\n }\n process.stderr.write(\"parquetlens: bun not found, falling back to plain output\\n\");\n } else {\n const { runTui } = await importTuiModule();\n const maxRows = limitSpecified ? options.limit : undefined;\n await runTui(input, { columns: options.columns, maxRows });\n return;\n }\n }\n\n const readOptions: ParquetReadOptions = {\n batchSize: 1024,\n columns: options.columns.length > 0 ? options.columns : undefined,\n limit: options.schemaOnly ? 0 : options.limit,\n };\n\n const table = await loadTable(input, readOptions);\n\n if (options.showSchema || options.schemaOnly) {\n const rowsCount = totalRows(table);\n const title = input ? path.basename(input) : \"stdin\";\n const limitSuffix = readOptions.limit ? ` (limit ${readOptions.limit})` : \"\";\n process.stdout.write(`file: ${title}\\nrows loaded: ${rowsCount}${limitSuffix}\\n`);\n process.stdout.write(\"schema:\\n\");\n process.stdout.write(`${formatSchema(table)}\\n`);\n }\n\n if (options.schemaOnly) {\n return;\n }\n\n const rows = previewRows(table, options.limit, options.columns);\n\n if (options.json) {\n for (const row of rows) {\n process.stdout.write(`${JSON.stringify(row)}\\n`);\n }\n return;\n }\n\n console.table(rows);\n}\n\nfunction resolveTuiMode(mode: TuiMode, options: Options): boolean {\n if (mode === \"on\") {\n if (options.json || options.schemaOnly) {\n return false;\n }\n return true;\n }\n\n if (mode === \"off\") {\n return false;\n }\n\n return !options.json && !options.schemaOnly;\n}\n\nfunction isBunRuntime(): boolean {\n return !!process.versions.bun;\n}\n\nfunction spawnBun(argv: string[]): boolean {\n const bunCheck = spawnSync(\"bun\", [\"--version\"], { stdio: \"ignore\" });\n if (bunCheck.error || bunCheck.status !== 0) {\n return false;\n }\n\n const result = spawnSync(\"bun\", [__filename, ...argv.slice(1)], {\n stdio: \"inherit\",\n env: { ...process.env, PARQUETLENS_BUN: \"1\" },\n });\n\n process.exitCode = result.status ?? 1;\n return true;\n}\n\nasync function importTuiModule(): Promise<typeof import(\"./tui.js\")> {\n const extension = path.extname(__filename);\n const modulePath = extension === \".js\" ? \"./tui.js\" : \"./tui.tsx\";\n return import(modulePath);\n}\n\nmain().catch((error) => {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`parquetlens: ${message}\\n`);\n process.exitCode = 1;\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/main.ts"],"sourcesContent":["#!/usr/bin/env node\nimport {\n ParquetReadOptions,\n readParquetTableFromPath,\n readParquetTableFromStdin,\n readParquetTableFromUrl,\n resolveParquetUrl,\n} from \"@parquetlens/parquet-reader\";\nimport type { Table } from \"apache-arrow\";\nimport { spawnSync } from \"node:child_process\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// Polyfill __filename for ESM (tsx dev mode)\nconst __filename =\n typeof globalThis.__filename !== \"undefined\"\n ? globalThis.__filename\n : fileURLToPath(import.meta.url);\n\ntype TuiMode = \"auto\" | \"on\" | \"off\";\n\ntype Options = {\n limit: number;\n columns: string[];\n json: boolean;\n schemaOnly: boolean;\n showSchema: boolean;\n tuiMode: TuiMode;\n};\n\ntype ParsedArgs = {\n input?: string;\n options: Options;\n limitSpecified: boolean;\n help: boolean;\n error?: string;\n};\n\nconst DEFAULT_LIMIT = 20;\n\nfunction parseArgs(argv: string[]): ParsedArgs {\n const options: Options = {\n limit: DEFAULT_LIMIT,\n columns: [],\n json: false,\n schemaOnly: false,\n showSchema: true,\n tuiMode: \"auto\",\n };\n\n let input: string | undefined;\n let limitSpecified = false;\n\n for (let i = 0; i < argv.length; i += 1) {\n const arg = argv[i];\n\n if (arg === \"--\") {\n continue;\n }\n\n if (arg === \"-h\" || arg === \"--help\") {\n return { options, limitSpecified, help: true };\n }\n\n if (arg === \"--json\") {\n options.json = true;\n options.tuiMode = \"off\";\n continue;\n }\n\n if (arg === \"--tui\") {\n options.tuiMode = \"on\";\n continue;\n }\n\n if (arg === \"--plain\" || arg === \"--no-tui\") {\n options.tuiMode = \"off\";\n continue;\n }\n\n if (arg === \"--schema\") {\n options.schemaOnly = true;\n options.tuiMode = \"off\";\n continue;\n }\n\n if (arg === \"--no-schema\") {\n options.showSchema = false;\n continue;\n }\n\n const limitValue = readOptionValue(arg, \"--limit\", argv[i + 1]);\n if (limitValue) {\n const parsed = Number.parseInt(limitValue.value, 10);\n if (!Number.isFinite(parsed) || parsed < 0) {\n return {\n options,\n limitSpecified,\n help: false,\n error: `invalid --limit value: ${limitValue.value}`,\n };\n }\n options.limit = parsed;\n limitSpecified = true;\n if (limitValue.usedNext) {\n i += 1;\n }\n continue;\n }\n\n const columnsValue = readOptionValue(arg, \"--columns\", argv[i + 1]);\n if (columnsValue) {\n const rawColumns = columnsValue.value\n .split(\",\")\n .map((value) => value.trim())\n .filter(Boolean);\n options.columns = rawColumns;\n if (columnsValue.usedNext) {\n i += 1;\n }\n continue;\n }\n\n if (arg === \"-\") {\n if (input) {\n return { options, limitSpecified, help: false, error: \"unexpected extra argument: -\" };\n }\n input = arg;\n continue;\n }\n\n if (arg.startsWith(\"-\")) {\n return { options, limitSpecified, help: false, error: `unknown option: ${arg}` };\n }\n\n if (input) {\n return { options, limitSpecified, help: false, error: `unexpected extra argument: ${arg}` };\n }\n\n input = arg;\n }\n\n return { input, options, limitSpecified, help: false };\n}\n\nfunction readOptionValue(\n arg: string,\n name: \"--limit\" | \"--columns\",\n next?: string,\n): { value: string; usedNext: boolean } | null {\n if (arg === name) {\n if (!next || next.startsWith(\"-\")) {\n return null;\n }\n return { value: next, usedNext: true };\n }\n\n if (arg.startsWith(`${name}=`)) {\n return { value: arg.slice(name.length + 1), usedNext: false };\n }\n\n return null;\n}\n\nfunction printUsage(): void {\n const helpText = `parquetlens <file|url|-> [options]\n\noptions:\n --limit, --limit=<n> number of rows to show (default: ${DEFAULT_LIMIT})\n --columns, --columns=<c> comma-separated column list\n --schema print schema only\n --no-schema skip schema output\n --json output rows as json lines\n --tui open interactive viewer (default)\n --plain, --no-tui disable interactive viewer\n -h, --help show help\n\nexamples:\n parquetlens data.parquet --limit 25\n parquetlens data.parquet --columns=city,state\n parquetlens hf://datasets/cfahlgren1/hub-stats/daily_papers.parquet\n parquetlens https://huggingface.co/datasets/cfahlgren1/hub-stats/resolve/main/daily_papers.parquet\n parquetlens data.parquet --plain\n parquetlens - < input.parquet\n`;\n\n process.stdout.write(helpText);\n}\n\nfunction formatSchema(table: Table): string {\n const lines = table.schema.fields.map((field, index) => {\n const typeName = String(field.type);\n return `${index + 1}. ${field.name}: ${typeName}`;\n });\n\n return lines.join(\"\\n\");\n}\n\nfunction totalRows(table: Table): number {\n return table.batches.reduce((count, batch) => count + batch.numRows, 0);\n}\n\nfunction resolveColumns(table: Table, requested: string[]): { names: string[]; indices: number[] } {\n const fields = table.schema.fields;\n const nameToIndex = new Map<string, number>();\n\n fields.forEach((field, index) => {\n nameToIndex.set(field.name, index);\n });\n\n const names = requested.length > 0 ? requested : fields.map((field) => field.name);\n const missing = names.filter((name) => !nameToIndex.has(name));\n\n if (missing.length > 0) {\n throw new Error(`unknown columns: ${missing.join(\", \")}`);\n }\n\n return {\n names,\n indices: names.map((name) => nameToIndex.get(name) ?? -1),\n };\n}\n\nfunction formatCell(value: unknown): unknown {\n if (value === null || value === undefined) {\n return null;\n }\n\n if (typeof value === \"bigint\") {\n return value.toString();\n }\n\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (value instanceof Uint8Array) {\n return `Uint8Array(${value.length})`;\n }\n\n if (typeof value === \"object\") {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n }\n\n return value;\n}\n\nfunction previewRows(\n table: Table,\n limit: number,\n requestedColumns: string[],\n): Record<string, unknown>[] {\n const { names, indices } = resolveColumns(table, requestedColumns);\n const rows: Record<string, unknown>[] = [];\n\n for (const batch of table.batches) {\n const vectors = indices.map((index) => batch.getChildAt(index));\n\n for (let rowIndex = 0; rowIndex < batch.numRows; rowIndex += 1) {\n if (rows.length >= limit) {\n return rows;\n }\n\n const row: Record<string, unknown> = {};\n\n for (let colIndex = 0; colIndex < names.length; colIndex += 1) {\n const vector = vectors[colIndex];\n row[names[colIndex]] = formatCell(vector?.get(rowIndex));\n }\n\n rows.push(row);\n }\n }\n\n return rows;\n}\n\nasync function loadTable(\n input: string | undefined,\n readOptions: ParquetReadOptions,\n): Promise<Table> {\n const stdinFallback = process.stdin.isTTY ? undefined : \"-\";\n const source = input ?? stdinFallback;\n\n if (!source) {\n throw new Error(\"missing input file (pass a path, URL, or pipe stdin)\");\n }\n\n if (source === \"-\") {\n return readParquetTableFromStdin(\"stdin.parquet\", readOptions);\n }\n\n if (resolveParquetUrl(source)) {\n return readParquetTableFromUrl(source, readOptions);\n }\n\n return readParquetTableFromPath(source, readOptions);\n}\n\nasync function main(): Promise<void> {\n const { input, options, limitSpecified, help, error } = parseArgs(process.argv.slice(2));\n\n if (help) {\n printUsage();\n return;\n }\n\n if (error) {\n process.stderr.write(`parquetlens: ${error}\\n`);\n printUsage();\n process.exitCode = 1;\n return;\n }\n\n const wantsTui = resolveTuiMode(options.tuiMode, options);\n if (wantsTui) {\n if (!input || input === \"-\") {\n process.stderr.write(\n \"parquetlens: tui mode requires a file path or URL (stdin not supported)\\n\",\n );\n process.exitCode = 1;\n return;\n }\n\n if (!process.stdin.isTTY || !process.stdout.isTTY) {\n process.stderr.write(\"parquetlens: tui mode requires a tty, falling back to plain output\\n\");\n } else if (!isBunRuntime()) {\n const spawned = spawnBun(process.argv.slice(1));\n if (spawned) {\n return;\n }\n process.stderr.write(\"parquetlens: bun not found, falling back to plain output\\n\");\n } else {\n const { runTui } = await importTuiModule();\n const maxRows = limitSpecified ? options.limit : undefined;\n\n await runTui(input, { columns: options.columns, maxRows });\n return;\n }\n }\n\n const readOptions: ParquetReadOptions = {\n batchSize: 1024,\n columns: options.columns.length > 0 ? options.columns : undefined,\n limit: options.schemaOnly ? 0 : options.limit,\n };\n\n const table = await loadTable(input, readOptions);\n\n if (options.showSchema || options.schemaOnly) {\n const rowsCount = totalRows(table);\n const title = input ? path.basename(input) : \"stdin\";\n const limitSuffix = readOptions.limit ? ` (limit ${readOptions.limit})` : \"\";\n process.stdout.write(`file: ${title}\\nrows loaded: ${rowsCount}${limitSuffix}\\n`);\n process.stdout.write(\"schema:\\n\");\n process.stdout.write(`${formatSchema(table)}\\n`);\n }\n\n if (options.schemaOnly) {\n return;\n }\n\n const rows = previewRows(table, options.limit, options.columns);\n\n if (options.json) {\n for (const row of rows) {\n process.stdout.write(`${JSON.stringify(row)}\\n`);\n }\n return;\n }\n\n console.table(rows);\n}\n\nfunction resolveTuiMode(mode: TuiMode, options: Options): boolean {\n if (mode === \"on\") {\n if (options.json || options.schemaOnly) {\n return false;\n }\n return true;\n }\n\n if (mode === \"off\") {\n return false;\n }\n\n return !options.json && !options.schemaOnly;\n}\n\nfunction isBunRuntime(): boolean {\n return !!process.versions.bun;\n}\n\nfunction spawnBun(argv: string[]): boolean {\n const bunCheck = spawnSync(\"bun\", [\"--version\"], { stdio: \"ignore\" });\n if (bunCheck.error || bunCheck.status !== 0) {\n return false;\n }\n\n const result = spawnSync(\"bun\", [__filename, ...argv.slice(1)], {\n stdio: \"inherit\",\n env: { ...process.env, PARQUETLENS_BUN: \"1\" },\n });\n\n process.exitCode = result.status ?? 1;\n return true;\n}\n\nasync function importTuiModule(): Promise<typeof import(\"./tui.js\")> {\n const extension = path.extname(__filename);\n const modulePath = extension === \".js\" ? \"./tui.js\" : \"./tui.tsx\";\n return import(modulePath);\n}\n\nmain().catch((error) => {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`parquetlens: ${message}\\n`);\n process.exitCode = 1;\n});\n"],"mappings":"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","names":[]}
|
package/dist/tui.js
CHANGED
|
@@ -5,13 +5,14 @@ const require = createRequire(import.meta.url);
|
|
|
5
5
|
const __filename = fileURLToPath(import.meta.url);
|
|
6
6
|
const __dirname = dirname(__filename);
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
} from "./chunk-
|
|
8
|
+
openParquetSource
|
|
9
|
+
} from "./chunk-NRRDNC7S.js";
|
|
10
10
|
|
|
11
11
|
// src/tui.tsx
|
|
12
12
|
import { createCliRenderer } from "@opentui/core";
|
|
13
13
|
import { createRoot, useKeyboard, useTerminalDimensions } from "@opentui/react";
|
|
14
|
-
import {
|
|
14
|
+
import { spawnSync } from "child_process";
|
|
15
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
15
16
|
import { Fragment, jsx, jsxs } from "@opentui/react/jsx-runtime";
|
|
16
17
|
var TOP_BAR_LINES = 3;
|
|
17
18
|
var FOOTER_LINES = 4;
|
|
@@ -37,8 +38,8 @@ var THEME = {
|
|
|
37
38
|
muted: "#6272a4",
|
|
38
39
|
stripe: "#252733"
|
|
39
40
|
};
|
|
40
|
-
async function runTui(
|
|
41
|
-
const source = await
|
|
41
|
+
async function runTui(input, options) {
|
|
42
|
+
const source = await openParquetSource(input);
|
|
42
43
|
const renderer = await createCliRenderer({
|
|
43
44
|
exitOnCtrlC: true,
|
|
44
45
|
useAlternateScreen: true,
|
|
@@ -52,12 +53,11 @@ async function runTui(filePath, options) {
|
|
|
52
53
|
root.unmount();
|
|
53
54
|
renderer.destroy();
|
|
54
55
|
};
|
|
55
|
-
root.render(/* @__PURE__ */ jsx(App, { source, filePath, options, onExit: handleExit }));
|
|
56
|
+
root.render(/* @__PURE__ */ jsx(App, { source, filePath: input, options, onExit: handleExit }));
|
|
56
57
|
}
|
|
57
58
|
function App({ source, filePath, options, onExit }) {
|
|
58
59
|
const { width, height } = useTerminalDimensions();
|
|
59
60
|
const pageSize = Math.max(1, height - RESERVED_LINES);
|
|
60
|
-
const maxOffset = options.maxRows === void 0 ? void 0 : Math.max(0, options.maxRows - pageSize);
|
|
61
61
|
const [offset, setOffset] = useState(0);
|
|
62
62
|
const [xOffset, setXOffset] = useState(0);
|
|
63
63
|
const [grid, setGrid] = useState({ columns: [], rows: [] });
|
|
@@ -65,11 +65,21 @@ function App({ source, filePath, options, onExit }) {
|
|
|
65
65
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
|
66
66
|
const [loading, setLoading] = useState(true);
|
|
67
67
|
const [error, setError] = useState(null);
|
|
68
|
+
const [notice, setNotice] = useState(null);
|
|
68
69
|
const [metadata, setMetadata] = useState(null);
|
|
70
|
+
const [knownTotalRows, setKnownTotalRows] = useState(null);
|
|
71
|
+
const noticeTimer = useRef(null);
|
|
72
|
+
const effectiveTotal = options.maxRows ?? knownTotalRows;
|
|
73
|
+
const maxOffset = effectiveTotal === void 0 || effectiveTotal === null ? void 0 : Math.max(0, effectiveTotal - pageSize);
|
|
69
74
|
const sidebarWidth = sidebarOpen ? Math.min(width, Math.max(SIDEBAR_MIN_WIDTH, Math.floor(width * SIDEBAR_WIDTH_RATIO))) : 0;
|
|
70
75
|
const tableWidth = Math.max(0, width - (sidebarOpen ? sidebarWidth + PANEL_GAP : 0));
|
|
71
76
|
const tableContentWidth = Math.max(0, tableWidth - CONTENT_BORDER_WIDTH);
|
|
72
77
|
const columnsToRead = options.columns;
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
return () => {
|
|
80
|
+
void source.close();
|
|
81
|
+
};
|
|
82
|
+
}, [source]);
|
|
73
83
|
useEffect(() => {
|
|
74
84
|
let canceled = false;
|
|
75
85
|
const loadWindow = async () => {
|
|
@@ -94,6 +104,9 @@ function App({ source, filePath, options, onExit }) {
|
|
|
94
104
|
);
|
|
95
105
|
if (!canceled) {
|
|
96
106
|
setGrid({ columns, rows });
|
|
107
|
+
if (rows.length < limit) {
|
|
108
|
+
setKnownTotalRows(offset + rows.length);
|
|
109
|
+
}
|
|
97
110
|
}
|
|
98
111
|
} catch (caught) {
|
|
99
112
|
const message = caught instanceof Error ? caught.message : String(caught);
|
|
@@ -145,6 +158,27 @@ function App({ source, filePath, options, onExit }) {
|
|
|
145
158
|
return { row: nextRow, col: nextCol };
|
|
146
159
|
});
|
|
147
160
|
}, [grid.columns.length, grid.rows.length]);
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
if (error) {
|
|
163
|
+
setSidebarOpen(true);
|
|
164
|
+
}
|
|
165
|
+
}, [error]);
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
return () => {
|
|
168
|
+
if (noticeTimer.current) {
|
|
169
|
+
clearTimeout(noticeTimer.current);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}, []);
|
|
173
|
+
const showNotice = (message) => {
|
|
174
|
+
setNotice(message);
|
|
175
|
+
if (noticeTimer.current) {
|
|
176
|
+
clearTimeout(noticeTimer.current);
|
|
177
|
+
}
|
|
178
|
+
noticeTimer.current = setTimeout(() => {
|
|
179
|
+
setNotice(null);
|
|
180
|
+
}, 2e3);
|
|
181
|
+
};
|
|
148
182
|
useKeyboard((key) => {
|
|
149
183
|
if (key.ctrl && key.name === "c" || key.name === "escape" || key.name === "q") {
|
|
150
184
|
if (sidebarOpen && key.name === "escape") {
|
|
@@ -194,6 +228,15 @@ function App({ source, filePath, options, onExit }) {
|
|
|
194
228
|
setSidebarOpen((current) => !current);
|
|
195
229
|
return;
|
|
196
230
|
}
|
|
231
|
+
if (key.name === "e" && error) {
|
|
232
|
+
setSidebarOpen(true);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (key.name === "y" && error) {
|
|
236
|
+
const copied = copyToClipboard(error);
|
|
237
|
+
showNotice(copied ? "copied error to clipboard" : "clipboard unavailable");
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
197
240
|
if (key.name === "left" || key.name === "h") {
|
|
198
241
|
setXOffset(
|
|
199
242
|
(current) => clampScroll(findScrollStop(current, gridLines.scrollStops, -1), maxScrollX)
|
|
@@ -207,7 +250,8 @@ function App({ source, filePath, options, onExit }) {
|
|
|
207
250
|
}
|
|
208
251
|
});
|
|
209
252
|
const visibleLines = applyHorizontalScroll(gridLines, tableContentWidth, xOffset, pageSize);
|
|
210
|
-
const detail = buildDetail(selection, grid, offset);
|
|
253
|
+
const detail = error ? buildErrorDetail(error) : buildDetail(selection, grid, offset);
|
|
254
|
+
const detailTitle = error ? "error detail" : "cell detail";
|
|
211
255
|
const metaFlags = getMetadataFlags(metadata);
|
|
212
256
|
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", width: "100%", height: "100%", backgroundColor: THEME.background, children: [
|
|
213
257
|
/* @__PURE__ */ jsx("box", { backgroundColor: THEME.header, border: true, borderColor: THEME.border, children: renderHeader({
|
|
@@ -217,7 +261,7 @@ function App({ source, filePath, options, onExit }) {
|
|
|
217
261
|
columns: grid.columns.length,
|
|
218
262
|
loading,
|
|
219
263
|
error,
|
|
220
|
-
maxRows:
|
|
264
|
+
maxRows: effectiveTotal ?? void 0,
|
|
221
265
|
optimized: metaFlags.optimized,
|
|
222
266
|
createdBy: metaFlags.createdBy
|
|
223
267
|
}) }),
|
|
@@ -291,7 +335,7 @@ function App({ source, filePath, options, onExit }) {
|
|
|
291
335
|
backgroundColor: THEME.panel,
|
|
292
336
|
border: true,
|
|
293
337
|
borderColor: THEME.border,
|
|
294
|
-
title:
|
|
338
|
+
title: detailTitle,
|
|
295
339
|
titleAlignment: "left",
|
|
296
340
|
children: [
|
|
297
341
|
/* @__PURE__ */ jsx("text", { wrapMode: "none", truncate: true, fg: THEME.muted, children: "press esc/x to close" }),
|
|
@@ -322,7 +366,7 @@ function App({ source, filePath, options, onExit }) {
|
|
|
322
366
|
}
|
|
323
367
|
) : null
|
|
324
368
|
] }),
|
|
325
|
-
/* @__PURE__ */ jsx("box", { backgroundColor: THEME.header, border: true, borderColor: THEME.border, children: renderFooter() })
|
|
369
|
+
/* @__PURE__ */ jsx("box", { backgroundColor: THEME.header, border: true, borderColor: THEME.border, children: renderFooter(Boolean(error), notice) })
|
|
326
370
|
] });
|
|
327
371
|
}
|
|
328
372
|
function renderHeader(props) {
|
|
@@ -356,12 +400,16 @@ function renderHeader(props) {
|
|
|
356
400
|
optimized ? /* @__PURE__ */ jsx("text", { wrapMode: "none", fg: THEME.badgeText, bg: THEME.badge, children: " \u2713 OPTIMIZED " }) : null
|
|
357
401
|
] });
|
|
358
402
|
}
|
|
359
|
-
function renderFooterLine() {
|
|
360
|
-
|
|
403
|
+
function renderFooterLine(hasError) {
|
|
404
|
+
const errorHint = hasError ? " | e view error | y copy error" : "";
|
|
405
|
+
return `q exit | arrows/jk scroll | pgup/pgdn page | h/l col jump | mouse wheel scroll | click cell for detail | s/enter toggle panel${errorHint}`;
|
|
361
406
|
}
|
|
362
|
-
function renderFooter() {
|
|
363
|
-
const controls = renderFooterLine();
|
|
364
|
-
return /* @__PURE__ */
|
|
407
|
+
function renderFooter(hasError, notice) {
|
|
408
|
+
const controls = renderFooterLine(hasError);
|
|
409
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", width: "100%", children: [
|
|
410
|
+
notice ? /* @__PURE__ */ jsx("text", { wrapMode: "none", truncate: true, fg: THEME.badge, children: notice }) : null,
|
|
411
|
+
/* @__PURE__ */ jsx("text", { wrapMode: "none", truncate: true, fg: THEME.muted, children: controls })
|
|
412
|
+
] });
|
|
365
413
|
}
|
|
366
414
|
function buildGridLines(grid, offset, targetWidth) {
|
|
367
415
|
const columns = grid.columns.length > 0 ? grid.columns : [{ name: "(loading)", type: "" }];
|
|
@@ -522,6 +570,11 @@ ${columnType}
|
|
|
522
570
|
|
|
523
571
|
${value}`;
|
|
524
572
|
}
|
|
573
|
+
function buildErrorDetail(message) {
|
|
574
|
+
return `error
|
|
575
|
+
|
|
576
|
+
${message}`;
|
|
577
|
+
}
|
|
525
578
|
function getMetadataFlags(metadata) {
|
|
526
579
|
if (!metadata) {
|
|
527
580
|
return { optimized: false };
|
|
@@ -570,6 +623,24 @@ function formatCell(value) {
|
|
|
570
623
|
function formatArrowType(type) {
|
|
571
624
|
return type.toString();
|
|
572
625
|
}
|
|
626
|
+
function copyToClipboard(value) {
|
|
627
|
+
const platform = process.platform;
|
|
628
|
+
const candidates = [];
|
|
629
|
+
if (platform === "darwin") {
|
|
630
|
+
candidates.push(["pbcopy", []]);
|
|
631
|
+
} else if (platform === "win32") {
|
|
632
|
+
candidates.push(["clip", []]);
|
|
633
|
+
} else {
|
|
634
|
+
candidates.push(["wl-copy", []], ["xclip", ["-selection", "clipboard"]]);
|
|
635
|
+
}
|
|
636
|
+
for (const [command, args] of candidates) {
|
|
637
|
+
const result = spawnSync(command, args, { input: value });
|
|
638
|
+
if (!result.error && result.status === 0) {
|
|
639
|
+
return true;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
return false;
|
|
643
|
+
}
|
|
573
644
|
export {
|
|
574
645
|
runTui
|
|
575
646
|
};
|
package/dist/tui.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tui.tsx"],"sourcesContent":["import { createCliRenderer } from \"@opentui/core\";\nimport { createRoot, useKeyboard, useTerminalDimensions } from \"@opentui/react\";\nimport React, { useEffect, useMemo, useState } from \"react\";\n\nimport type {\n ParquetBufferSource,\n ParquetFileMetadata,\n ParquetReadOptions,\n} from \"@parquetlens/parquet-reader\";\nimport { openParquetBufferFromPath } from \"@parquetlens/parquet-reader\";\n\ntype TuiOptions = {\n columns: string[];\n maxRows?: number;\n batchSize?: number;\n};\n\ntype ColumnInfo = {\n name: string;\n type: string;\n};\n\ntype GridState = {\n columns: ColumnInfo[];\n rows: string[][];\n};\n\ntype GridLines = {\n headerNameLine: string;\n headerTypeLine: string;\n separatorLine: string;\n rowLines: string[];\n maxLineLength: number;\n columnRanges: Array<{ start: number; end: number }>;\n scrollStops: number[];\n};\n\nconst TOP_BAR_LINES = 3;\nconst FOOTER_LINES = 4;\nconst TABLE_BORDER_LINES = 2;\nconst TABLE_HEADER_LINES = 3;\nconst RESERVED_LINES = TOP_BAR_LINES + FOOTER_LINES + TABLE_BORDER_LINES + TABLE_HEADER_LINES;\nconst DEFAULT_COLUMN_WIDTH = 6;\nconst MAX_COLUMN_WIDTH = 40;\nconst SCROLL_STEP = 3;\nconst SIDEBAR_WIDTH_RATIO = 0.35;\nconst SIDEBAR_MIN_WIDTH = 24;\nconst CONTENT_BORDER_WIDTH = 2;\nconst PANEL_GAP = 1;\n\nconst THEME = {\n background: \"#1e1f29\",\n panel: \"#22232e\",\n header: \"#2d2f3d\",\n border: \"#44475a\",\n accent: \"#bd93f9\",\n badge: \"#50fa7b\",\n badgeText: \"#1e1f29\",\n text: \"#c5cee0\",\n muted: \"#6272a4\",\n stripe: \"#252733\",\n};\n\nexport async function runTui(filePath: string, options: TuiOptions): Promise<void> {\n const source = await openParquetBufferFromPath(filePath);\n const renderer = await createCliRenderer({\n exitOnCtrlC: true,\n useAlternateScreen: true,\n useConsole: false,\n useMouse: true,\n enableMouseMovement: true,\n });\n renderer.setTerminalTitle(\"parquetlens\");\n const root = createRoot(renderer);\n\n const handleExit = () => {\n root.unmount();\n renderer.destroy();\n };\n\n root.render(<App source={source} filePath={filePath} options={options} onExit={handleExit} />);\n}\n\ntype AppProps = {\n source: ParquetBufferSource;\n filePath: string;\n options: TuiOptions;\n onExit: () => void;\n};\n\nfunction App({ source, filePath, options, onExit }: AppProps) {\n const { width, height } = useTerminalDimensions();\n const pageSize = Math.max(1, height - RESERVED_LINES);\n const maxOffset =\n options.maxRows === undefined ? undefined : Math.max(0, options.maxRows - pageSize);\n\n const [offset, setOffset] = useState(0);\n const [xOffset, setXOffset] = useState(0);\n const [grid, setGrid] = useState<GridState>({ columns: [], rows: [] } as GridState);\n const [selection, setSelection] = useState<{ row: number; col: number } | null>(null);\n const [sidebarOpen, setSidebarOpen] = useState(false);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [metadata, setMetadata] = useState<ParquetFileMetadata | null>(null);\n const sidebarWidth = sidebarOpen\n ? Math.min(width, Math.max(SIDEBAR_MIN_WIDTH, Math.floor(width * SIDEBAR_WIDTH_RATIO)))\n : 0;\n const tableWidth = Math.max(0, width - (sidebarOpen ? sidebarWidth + PANEL_GAP : 0));\n const tableContentWidth = Math.max(0, tableWidth - CONTENT_BORDER_WIDTH);\n\n const columnsToRead = options.columns;\n\n useEffect(() => {\n let canceled = false;\n\n const loadWindow = async () => {\n setLoading(true);\n setError(null);\n try {\n const limit = options.maxRows\n ? Math.max(0, Math.min(pageSize, options.maxRows - offset))\n : pageSize;\n const readOptions: ParquetReadOptions = {\n batchSize: options.batchSize ?? 1024,\n columns: columnsToRead.length > 0 ? columnsToRead : undefined,\n limit,\n offset,\n };\n const table = await source.readTable(readOptions);\n const columns: ColumnInfo[] = table.schema.fields.map((field) => ({\n name: field.name,\n type: formatArrowType(field.type),\n }));\n const rows = tableToRows(\n table,\n columns.map((c) => c.name),\n );\n\n if (!canceled) {\n setGrid({ columns, rows });\n }\n } catch (caught) {\n const message = caught instanceof Error ? caught.message : String(caught);\n if (!canceled) {\n setError(message);\n }\n } finally {\n if (!canceled) {\n setLoading(false);\n }\n }\n };\n\n loadWindow();\n\n return () => {\n canceled = true;\n };\n }, [columnsToRead, offset, options.batchSize, options.maxRows, pageSize, source]);\n\n useEffect(() => {\n let canceled = false;\n source\n .readMetadata()\n .then((meta) => {\n if (!canceled) {\n setMetadata(meta);\n }\n })\n .catch(() => {\n if (!canceled) {\n setMetadata(null);\n }\n });\n\n return () => {\n canceled = true;\n };\n }, [source]);\n\n const gridLines = useMemo(\n () => buildGridLines(grid, offset, tableContentWidth),\n [grid, offset, tableContentWidth],\n );\n const maxScrollX = Math.max(0, gridLines.maxLineLength - tableContentWidth);\n\n useEffect(() => {\n setXOffset((current) => Math.min(current, maxScrollX));\n }, [gridLines.maxLineLength, maxScrollX, tableContentWidth]);\n\n useEffect(() => {\n if (grid.rows.length === 0 || grid.columns.length === 0) {\n setSelection(null);\n return;\n }\n\n setSelection((current) => {\n const nextRow = current ? Math.min(current.row, grid.rows.length - 1) : 0;\n const nextCol = current ? Math.min(current.col, grid.columns.length - 1) : 0;\n return { row: nextRow, col: nextCol };\n });\n }, [grid.columns.length, grid.rows.length]);\n\n useKeyboard((key) => {\n if ((key.ctrl && key.name === \"c\") || key.name === \"escape\" || key.name === \"q\") {\n if (sidebarOpen && key.name === \"escape\") {\n setSidebarOpen(false);\n return;\n }\n onExit();\n return;\n }\n\n const clampOffset = (value: number) => {\n const clamped = Math.max(0, value);\n return maxOffset === undefined ? clamped : Math.min(clamped, maxOffset);\n };\n\n if (key.name === \"down\" || key.name === \"j\") {\n setOffset((current) => clampOffset(current + 1));\n return;\n }\n\n if (key.name === \"up\" || key.name === \"k\") {\n setOffset((current) => clampOffset(current - 1));\n return;\n }\n\n if (key.name === \"pagedown\" || key.name === \"space\") {\n setOffset((current) => clampOffset(current + pageSize));\n return;\n }\n\n if (key.name === \"pageup\") {\n setOffset((current) => clampOffset(current - pageSize));\n return;\n }\n\n if (key.name === \"home\" || (key.name === \"g\" && !key.shift)) {\n setOffset(0);\n return;\n }\n\n if ((key.name === \"end\" || (key.name === \"g\" && key.shift)) && maxOffset !== undefined) {\n setOffset(maxOffset);\n return;\n }\n\n if (key.name === \"return\" || key.name === \"enter\") {\n setSidebarOpen((current) => !current);\n return;\n }\n\n if (key.name === \"x\") {\n setSidebarOpen(false);\n return;\n }\n\n if (key.name === \"s\") {\n setSidebarOpen((current) => !current);\n return;\n }\n\n if (key.name === \"left\" || key.name === \"h\") {\n setXOffset((current) =>\n clampScroll(findScrollStop(current, gridLines.scrollStops, -1), maxScrollX),\n );\n return;\n }\n\n if (key.name === \"right\" || key.name === \"l\") {\n setXOffset((current) =>\n clampScroll(findScrollStop(current, gridLines.scrollStops, 1), maxScrollX),\n );\n }\n });\n\n const visibleLines = applyHorizontalScroll(gridLines, tableContentWidth, xOffset, pageSize);\n const detail = buildDetail(selection, grid, offset);\n const metaFlags = getMetadataFlags(metadata);\n\n return (\n <box flexDirection=\"column\" width=\"100%\" height=\"100%\" backgroundColor={THEME.background}>\n <box backgroundColor={THEME.header} border borderColor={THEME.border}>\n {renderHeader({\n filePath,\n offset,\n rows: grid.rows.length,\n columns: grid.columns.length,\n loading,\n error,\n maxRows: options.maxRows,\n optimized: metaFlags.optimized,\n createdBy: metaFlags.createdBy,\n })}\n </box>\n <box flexGrow={1} flexDirection=\"row\" gap={PANEL_GAP}>\n <box\n backgroundColor={THEME.panel}\n border\n borderColor={THEME.border}\n flexGrow={1}\n width={sidebarOpen ? tableWidth : \"100%\"}\n onMouseScroll={(event) => {\n if (!event.scroll) {\n return;\n }\n\n const delta = Math.max(1, event.scroll.delta);\n const step = delta * SCROLL_STEP;\n\n if (event.scroll.direction === \"up\") {\n setOffset((current) => Math.max(0, current - step));\n } else if (event.scroll.direction === \"down\") {\n setOffset((current) => {\n const next = current + step;\n return maxOffset === undefined ? next : Math.min(next, maxOffset);\n });\n } else if (event.scroll.direction === \"left\") {\n setXOffset((current) => clampScroll(current - step, maxScrollX));\n } else if (event.scroll.direction === \"right\") {\n setXOffset((current) => clampScroll(current + step, maxScrollX));\n }\n }}\n >\n <text wrapMode=\"none\" truncate fg={THEME.accent}>\n {visibleLines.headerName}\n </text>\n <text wrapMode=\"none\" truncate fg={THEME.muted}>\n {visibleLines.headerType}\n </text>\n <text wrapMode=\"none\" truncate fg={THEME.border}>\n {visibleLines.separator}\n </text>\n {visibleLines.rows.map((line, index) => {\n const isSelected = selection?.row === index;\n return (\n <text\n key={`row-${index}`}\n wrapMode=\"none\"\n truncate\n fg={THEME.text}\n bg={isSelected ? THEME.header : index % 2 === 0 ? THEME.background : THEME.stripe}\n onMouseDown={(event) => {\n const target = event.target;\n if (!target) {\n return;\n }\n const localX = Math.max(0, event.x - target.x);\n const absoluteX = localX + xOffset;\n const colIndex = findColumnIndex(absoluteX, gridLines.columnRanges);\n if (colIndex >= 0) {\n setSelection({ row: index, col: colIndex });\n setSidebarOpen(true);\n }\n }}\n >\n {line}\n </text>\n );\n })}\n </box>\n {sidebarOpen ? (\n <box\n width=\"35%\"\n minWidth={24}\n backgroundColor={THEME.panel}\n border\n borderColor={THEME.border}\n title=\"cell detail\"\n titleAlignment=\"left\"\n >\n <text wrapMode=\"none\" truncate fg={THEME.muted}>\n press esc/x to close\n </text>\n <scrollbox scrollY flexGrow={1} backgroundColor={THEME.panel}>\n <text\n wrapMode=\"word\"\n fg={THEME.text}\n selectable\n selectionBg={THEME.accent}\n selectionFg={THEME.background}\n >\n {detail}\n </text>\n </scrollbox>\n <text\n wrapMode=\"none\"\n truncate\n fg={THEME.accent}\n onMouseDown={() => {\n setSidebarOpen(false);\n }}\n >\n [ close ]\n </text>\n </box>\n ) : null}\n </box>\n <box backgroundColor={THEME.header} border borderColor={THEME.border}>\n {renderFooter()}\n </box>\n </box>\n );\n}\n\ntype HeaderProps = {\n filePath: string;\n offset: number;\n rows: number;\n columns: number;\n loading: boolean;\n error: string | null;\n maxRows?: number;\n createdBy?: string;\n optimized: boolean;\n};\n\nfunction renderHeader(props: HeaderProps) {\n const { filePath, offset, rows, columns, loading, error, maxRows, createdBy, optimized } = props;\n\n const start = rows > 0 ? offset + 1 : offset;\n const end = rows > 0 ? offset + rows : offset;\n const totalText = maxRows !== undefined ? `of ${maxRows.toLocaleString()}` : \"\";\n const fileName = filePath.split(\"/\").pop() ?? filePath;\n\n if (error) {\n return (\n <box flexDirection=\"row\" alignItems=\"center\" gap={2} width=\"100%\">\n <text wrapMode=\"none\" fg={THEME.accent}>\n {\"◈ parquetlens\"}\n </text>\n <text wrapMode=\"none\" fg=\"#ef4444\">\n {\"error: \" + error}\n </text>\n </box>\n );\n }\n\n return (\n <box flexDirection=\"row\" alignItems=\"center\" gap={2} width=\"100%\">\n <text wrapMode=\"none\" fg={THEME.accent}>\n {\"◈ parquetlens\"}\n </text>\n <text wrapMode=\"none\" fg={THEME.muted}>\n {\"│\"}\n </text>\n <text wrapMode=\"none\" fg={THEME.text}>\n {fileName}\n </text>\n <text wrapMode=\"none\" fg={THEME.muted}>\n {\"│\"}\n </text>\n <text wrapMode=\"none\" fg={THEME.muted}>\n {\"rows \"}\n </text>\n <text wrapMode=\"none\" fg={THEME.text}>\n {`${start.toLocaleString()}-${end.toLocaleString()} ${totalText}`}\n </text>\n <text wrapMode=\"none\" fg={THEME.muted}>\n {\"│\"}\n </text>\n <text wrapMode=\"none\" fg={THEME.muted}>\n {\"cols \"}\n </text>\n <text wrapMode=\"none\" fg={THEME.text}>\n {columns.toString()}\n </text>\n {createdBy ? (\n <>\n <text wrapMode=\"none\" fg={THEME.muted}>\n {\"│\"}\n </text>\n <text wrapMode=\"none\" fg={THEME.muted} truncate>\n {createdBy}\n </text>\n </>\n ) : null}\n <box flexGrow={1} />\n {loading ? (\n <text wrapMode=\"none\" fg={THEME.badge}>\n {\"● loading\"}\n </text>\n ) : null}\n {optimized ? (\n <text wrapMode=\"none\" fg={THEME.badgeText} bg={THEME.badge}>\n {\" ✓ OPTIMIZED \"}\n </text>\n ) : null}\n </box>\n );\n}\n\nfunction renderFooterLine(): string {\n return \"q exit | arrows/jk scroll | pgup/pgdn page | h/l col jump | mouse wheel scroll | click cell for detail | s/enter toggle panel\";\n}\n\nfunction renderFooter() {\n const controls = renderFooterLine();\n\n return (\n <box flexDirection=\"column\" width=\"100%\">\n <text wrapMode=\"none\" truncate fg={THEME.muted}>\n {controls}\n </text>\n </box>\n );\n}\n\nfunction buildGridLines(grid: GridState, offset: number, targetWidth: number): GridLines {\n const columns: ColumnInfo[] =\n grid.columns.length > 0 ? grid.columns : [{ name: \"(loading)\", type: \"\" }];\n const rows = grid.rows;\n\n const rowNumberWidth = Math.max(String(offset + rows.length).length, 3);\n const columnWidths = columns.map((col, index) => {\n const longestCell = rows.reduce(\n (max, row) => {\n const value = row[index] ?? \"\";\n return Math.max(max, value.length);\n },\n Math.max(col.name.length, col.type.length),\n );\n return Math.min(Math.max(longestCell, DEFAULT_COLUMN_WIDTH), MAX_COLUMN_WIDTH);\n });\n\n const headerNames = [\"#\", ...columns.map((c) => c.name)];\n const headerTypes = [\"\", ...columns.map((c) => c.type)];\n const headerWidths = [rowNumberWidth, ...columnWidths];\n const separatorWidth = headerWidths.length > 1 ? (headerWidths.length - 1) * 2 : 0;\n const baseLength = headerWidths.reduce((total, width) => total + width, 0) + separatorWidth;\n\n if (targetWidth > baseLength && headerWidths.length > 1) {\n headerWidths[headerWidths.length - 1] += targetWidth - baseLength;\n }\n const headerNameLine = buildLine(headerNames, headerWidths);\n const headerTypeLine = buildLine(headerTypes, headerWidths);\n const separatorLine = buildSeparator(headerWidths);\n const rowLines = rows.map((row, index) => {\n const rowIndex = String(offset + index + 1);\n const values = [rowIndex, ...row];\n return buildLine(values, headerWidths);\n });\n\n const { columnRanges, scrollStops } = buildColumnRanges(headerWidths);\n\n const maxLineLength = Math.max(\n headerNameLine.length,\n headerTypeLine.length,\n separatorLine.length,\n ...rowLines.map((line) => line.length),\n );\n\n return {\n headerNameLine,\n headerTypeLine,\n separatorLine,\n rowLines,\n maxLineLength,\n columnRanges,\n scrollStops,\n };\n}\n\nfunction applyHorizontalScroll(\n lines: GridLines,\n width: number,\n xOffset: number,\n pageSize: number,\n): { headerName: string; headerType: string; separator: string; rows: string[] } {\n const sliceLine = (line: string) => {\n if (width <= 0) {\n return \"\";\n }\n const sliced = xOffset <= 0 ? line.slice(0, width) : line.slice(xOffset, xOffset + width);\n return sliced.padEnd(width, \" \");\n };\n\n const rows = lines.rowLines.slice(0, pageSize).map(sliceLine);\n const emptyRow = width > 0 ? \" \".repeat(width) : \"\";\n while (rows.length < pageSize) {\n rows.push(emptyRow);\n }\n\n return {\n headerName: sliceLine(lines.headerNameLine),\n headerType: sliceLine(lines.headerTypeLine),\n separator: sliceLine(lines.separatorLine),\n rows,\n };\n}\n\nfunction buildLine(values: string[], widths: number[]): string {\n return values\n .map((value, index) => {\n const width = widths[index] ?? DEFAULT_COLUMN_WIDTH;\n return padCell(value, width);\n })\n .join(\" \");\n}\n\nfunction buildSeparator(widths: number[]): string {\n return \"\";\n}\n\nfunction padCell(value: string, width: number): string {\n const normalized = normalizeCell(value);\n if (normalized.length > width) {\n if (width <= 3) {\n return normalized.slice(0, width);\n }\n return `${normalized.slice(0, width - 3)}...`;\n }\n return normalized.padEnd(width, \" \");\n}\n\nfunction normalizeCell(value: string): string {\n return value.replace(/\\r?\\n/g, \"\\\\n\").replace(/\\t/g, \"\\\\t\");\n}\n\nfunction buildColumnRanges(widths: number[]): {\n columnRanges: Array<{ start: number; end: number }>;\n scrollStops: number[];\n} {\n const columnRanges: Array<{ start: number; end: number }> = [];\n const scrollStops: number[] = [0];\n let cursor = 0;\n\n for (let i = 0; i < widths.length; i += 1) {\n const width = widths[i];\n if (i > 0) {\n const start = cursor;\n const end = cursor + width - 1;\n columnRanges.push({ start, end });\n scrollStops.push(start);\n }\n cursor += width;\n if (i < widths.length - 1) {\n cursor += 2;\n }\n }\n\n return { columnRanges, scrollStops };\n}\n\nfunction findColumnIndex(x: number, ranges: Array<{ start: number; end: number }>): number {\n for (let index = 0; index < ranges.length; index += 1) {\n const range = ranges[index];\n if (x >= range.start && x <= range.end) {\n return index;\n }\n }\n return -1;\n}\n\nfunction findScrollStop(current: number, stops: number[], direction: 1 | -1): number {\n if (direction > 0) {\n for (const stop of stops) {\n if (stop > current) {\n return stop;\n }\n }\n return current;\n }\n\n for (let index = stops.length - 1; index >= 0; index -= 1) {\n const stop = stops[index];\n if (stop < current) {\n return stop;\n }\n }\n\n return 0;\n}\n\nfunction clampScroll(value: number, max: number): number {\n if (value < 0) {\n return 0;\n }\n if (value > max) {\n return max;\n }\n return value;\n}\n\nfunction buildDetail(\n selection: { row: number; col: number } | null,\n grid: GridState,\n offset: number,\n): string {\n if (!selection || grid.columns.length === 0 || grid.rows.length === 0) {\n return \"click a cell to see full details\";\n }\n\n const rowIndex = Math.min(selection.row, grid.rows.length - 1);\n const colIndex = Math.min(selection.col, grid.columns.length - 1);\n const col = grid.columns[colIndex];\n const columnName = col?.name ?? \"(unknown)\";\n const columnType = col?.type ?? \"\";\n const value = grid.rows[rowIndex]?.[colIndex] ?? \"\";\n const absoluteRow = offset + rowIndex + 1;\n\n return `row ${absoluteRow} • ${columnName}\\n${columnType}\\n\\n${value}`;\n}\n\nfunction getMetadataFlags(metadata: ParquetFileMetadata | null): {\n optimized: boolean;\n createdBy?: string;\n} {\n if (!metadata) {\n return { optimized: false };\n }\n\n const raw = metadata.keyValueMetadata[\"content_defined_chunking\"];\n const normalized = raw?.toLowerCase?.() ?? \"\";\n const optimized =\n raw !== undefined && raw !== null && normalized !== \"false\" && normalized !== \"0\";\n\n return {\n optimized,\n createdBy: metadata.createdBy,\n };\n}\n\nfunction tableToRows(table: import(\"apache-arrow\").Table, columns: string[]): string[][] {\n const rows: string[][] = [];\n\n for (const batch of table.batches) {\n const vectors = columns.map((_, index) => batch.getChildAt(index));\n\n for (let rowIndex = 0; rowIndex < batch.numRows; rowIndex += 1) {\n const row = vectors.map((vector) => formatCell(vector?.get(rowIndex)));\n rows.push(row);\n }\n }\n\n return rows;\n}\n\nfunction formatCell(value: unknown): string {\n if (value === null || value === undefined) {\n return \"\";\n }\n\n if (typeof value === \"bigint\") {\n return value.toString();\n }\n\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (value instanceof Uint8Array) {\n return `Uint8Array(${value.length})`;\n }\n\n if (typeof value === \"object\") {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n }\n\n return String(value);\n}\n\nfunction formatArrowType(type: import(\"apache-arrow\").DataType): string {\n return type.toString();\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/tui.tsx"],"sourcesContent":["import { createCliRenderer } from \"@opentui/core\";\nimport { createRoot, useKeyboard, useTerminalDimensions } from \"@opentui/react\";\nimport { spawnSync } from \"node:child_process\";\nimport React, { useEffect, useMemo, useRef, useState } from \"react\";\n\nimport type {\n ParquetSource,\n ParquetFileMetadata,\n ParquetReadOptions,\n} from \"@parquetlens/parquet-reader\";\nimport { openParquetSource } from \"@parquetlens/parquet-reader\";\n\ntype TuiOptions = {\n columns: string[];\n maxRows?: number;\n batchSize?: number;\n};\n\ntype ColumnInfo = {\n name: string;\n type: string;\n};\n\ntype GridState = {\n columns: ColumnInfo[];\n rows: string[][];\n};\n\ntype GridLines = {\n headerNameLine: string;\n headerTypeLine: string;\n separatorLine: string;\n rowLines: string[];\n maxLineLength: number;\n columnRanges: Array<{ start: number; end: number }>;\n scrollStops: number[];\n};\n\nconst TOP_BAR_LINES = 3;\nconst FOOTER_LINES = 4;\nconst TABLE_BORDER_LINES = 2;\nconst TABLE_HEADER_LINES = 3;\nconst RESERVED_LINES = TOP_BAR_LINES + FOOTER_LINES + TABLE_BORDER_LINES + TABLE_HEADER_LINES;\nconst DEFAULT_COLUMN_WIDTH = 6;\nconst MAX_COLUMN_WIDTH = 40;\nconst SCROLL_STEP = 3;\nconst SIDEBAR_WIDTH_RATIO = 0.35;\nconst SIDEBAR_MIN_WIDTH = 24;\nconst CONTENT_BORDER_WIDTH = 2;\nconst PANEL_GAP = 1;\n\nconst THEME = {\n background: \"#1e1f29\",\n panel: \"#22232e\",\n header: \"#2d2f3d\",\n border: \"#44475a\",\n accent: \"#bd93f9\",\n badge: \"#50fa7b\",\n badgeText: \"#1e1f29\",\n text: \"#c5cee0\",\n muted: \"#6272a4\",\n stripe: \"#252733\",\n};\n\nexport async function runTui(input: string, options: TuiOptions): Promise<void> {\n const source = await openParquetSource(input);\n const renderer = await createCliRenderer({\n exitOnCtrlC: true,\n useAlternateScreen: true,\n useConsole: false,\n useMouse: true,\n enableMouseMovement: true,\n });\n renderer.setTerminalTitle(\"parquetlens\");\n const root = createRoot(renderer);\n\n const handleExit = () => {\n root.unmount();\n renderer.destroy();\n };\n\n root.render(<App source={source} filePath={input} options={options} onExit={handleExit} />);\n}\n\ntype AppProps = {\n source: ParquetSource;\n filePath: string;\n options: TuiOptions;\n onExit: () => void;\n};\n\nfunction App({ source, filePath, options, onExit }: AppProps) {\n const { width, height } = useTerminalDimensions();\n const pageSize = Math.max(1, height - RESERVED_LINES);\n\n const [offset, setOffset] = useState(0);\n const [xOffset, setXOffset] = useState(0);\n const [grid, setGrid] = useState<GridState>({ columns: [], rows: [] } as GridState);\n const [selection, setSelection] = useState<{ row: number; col: number } | null>(null);\n const [sidebarOpen, setSidebarOpen] = useState(false);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [notice, setNotice] = useState<string | null>(null);\n const [metadata, setMetadata] = useState<ParquetFileMetadata | null>(null);\n const [knownTotalRows, setKnownTotalRows] = useState<number | null>(null);\n const noticeTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const effectiveTotal = options.maxRows ?? knownTotalRows;\n const maxOffset =\n effectiveTotal === undefined || effectiveTotal === null\n ? undefined\n : Math.max(0, effectiveTotal - pageSize);\n const sidebarWidth = sidebarOpen\n ? Math.min(width, Math.max(SIDEBAR_MIN_WIDTH, Math.floor(width * SIDEBAR_WIDTH_RATIO)))\n : 0;\n const tableWidth = Math.max(0, width - (sidebarOpen ? sidebarWidth + PANEL_GAP : 0));\n const tableContentWidth = Math.max(0, tableWidth - CONTENT_BORDER_WIDTH);\n\n const columnsToRead = options.columns;\n\n useEffect(() => {\n return () => {\n void source.close();\n };\n }, [source]);\n\n useEffect(() => {\n let canceled = false;\n\n const loadWindow = async () => {\n setLoading(true);\n setError(null);\n try {\n const limit = options.maxRows\n ? Math.max(0, Math.min(pageSize, options.maxRows - offset))\n : pageSize;\n const readOptions: ParquetReadOptions = {\n batchSize: options.batchSize ?? 1024,\n columns: columnsToRead.length > 0 ? columnsToRead : undefined,\n limit,\n offset,\n };\n const table = await source.readTable(readOptions);\n const columns: ColumnInfo[] = table.schema.fields.map((field) => ({\n name: field.name,\n type: formatArrowType(field.type),\n }));\n const rows = tableToRows(\n table,\n columns.map((c) => c.name),\n );\n\n if (!canceled) {\n setGrid({ columns, rows });\n // Detect end of file: if we got fewer rows than requested, we know the total\n if (rows.length < limit) {\n setKnownTotalRows(offset + rows.length);\n }\n }\n } catch (caught) {\n const message = caught instanceof Error ? caught.message : String(caught);\n if (!canceled) {\n setError(message);\n }\n } finally {\n if (!canceled) {\n setLoading(false);\n }\n }\n };\n\n loadWindow();\n\n return () => {\n canceled = true;\n };\n }, [columnsToRead, offset, options.batchSize, options.maxRows, pageSize, source]);\n\n useEffect(() => {\n let canceled = false;\n source\n .readMetadata()\n .then((meta) => {\n if (!canceled) {\n setMetadata(meta);\n }\n })\n .catch(() => {\n if (!canceled) {\n setMetadata(null);\n }\n });\n\n return () => {\n canceled = true;\n };\n }, [source]);\n\n const gridLines = useMemo(\n () => buildGridLines(grid, offset, tableContentWidth),\n [grid, offset, tableContentWidth],\n );\n const maxScrollX = Math.max(0, gridLines.maxLineLength - tableContentWidth);\n\n useEffect(() => {\n setXOffset((current) => Math.min(current, maxScrollX));\n }, [gridLines.maxLineLength, maxScrollX, tableContentWidth]);\n\n useEffect(() => {\n if (grid.rows.length === 0 || grid.columns.length === 0) {\n setSelection(null);\n return;\n }\n\n setSelection((current) => {\n const nextRow = current ? Math.min(current.row, grid.rows.length - 1) : 0;\n const nextCol = current ? Math.min(current.col, grid.columns.length - 1) : 0;\n return { row: nextRow, col: nextCol };\n });\n }, [grid.columns.length, grid.rows.length]);\n\n useEffect(() => {\n if (error) {\n setSidebarOpen(true);\n }\n }, [error]);\n\n useEffect(() => {\n return () => {\n if (noticeTimer.current) {\n clearTimeout(noticeTimer.current);\n }\n };\n }, []);\n\n const showNotice = (message: string) => {\n setNotice(message);\n if (noticeTimer.current) {\n clearTimeout(noticeTimer.current);\n }\n noticeTimer.current = setTimeout(() => {\n setNotice(null);\n }, 2000);\n };\n\n useKeyboard((key) => {\n if ((key.ctrl && key.name === \"c\") || key.name === \"escape\" || key.name === \"q\") {\n if (sidebarOpen && key.name === \"escape\") {\n setSidebarOpen(false);\n return;\n }\n onExit();\n return;\n }\n\n const clampOffset = (value: number) => {\n const clamped = Math.max(0, value);\n return maxOffset === undefined ? clamped : Math.min(clamped, maxOffset);\n };\n\n if (key.name === \"down\" || key.name === \"j\") {\n setOffset((current) => clampOffset(current + 1));\n return;\n }\n\n if (key.name === \"up\" || key.name === \"k\") {\n setOffset((current) => clampOffset(current - 1));\n return;\n }\n\n if (key.name === \"pagedown\" || key.name === \"space\") {\n setOffset((current) => clampOffset(current + pageSize));\n return;\n }\n\n if (key.name === \"pageup\") {\n setOffset((current) => clampOffset(current - pageSize));\n return;\n }\n\n if (key.name === \"home\" || (key.name === \"g\" && !key.shift)) {\n setOffset(0);\n return;\n }\n\n if ((key.name === \"end\" || (key.name === \"g\" && key.shift)) && maxOffset !== undefined) {\n setOffset(maxOffset);\n return;\n }\n\n if (key.name === \"return\" || key.name === \"enter\") {\n setSidebarOpen((current) => !current);\n return;\n }\n\n if (key.name === \"x\") {\n setSidebarOpen(false);\n return;\n }\n\n if (key.name === \"s\") {\n setSidebarOpen((current) => !current);\n return;\n }\n\n if (key.name === \"e\" && error) {\n setSidebarOpen(true);\n return;\n }\n\n if (key.name === \"y\" && error) {\n const copied = copyToClipboard(error);\n showNotice(copied ? \"copied error to clipboard\" : \"clipboard unavailable\");\n return;\n }\n\n if (key.name === \"left\" || key.name === \"h\") {\n setXOffset((current) =>\n clampScroll(findScrollStop(current, gridLines.scrollStops, -1), maxScrollX),\n );\n return;\n }\n\n if (key.name === \"right\" || key.name === \"l\") {\n setXOffset((current) =>\n clampScroll(findScrollStop(current, gridLines.scrollStops, 1), maxScrollX),\n );\n }\n });\n\n const visibleLines = applyHorizontalScroll(gridLines, tableContentWidth, xOffset, pageSize);\n const detail = error ? buildErrorDetail(error) : buildDetail(selection, grid, offset);\n const detailTitle = error ? \"error detail\" : \"cell detail\";\n const metaFlags = getMetadataFlags(metadata);\n\n return (\n <box flexDirection=\"column\" width=\"100%\" height=\"100%\" backgroundColor={THEME.background}>\n <box backgroundColor={THEME.header} border borderColor={THEME.border}>\n {renderHeader({\n filePath,\n offset,\n rows: grid.rows.length,\n columns: grid.columns.length,\n loading,\n error,\n maxRows: effectiveTotal ?? undefined,\n optimized: metaFlags.optimized,\n createdBy: metaFlags.createdBy,\n })}\n </box>\n <box flexGrow={1} flexDirection=\"row\" gap={PANEL_GAP}>\n <box\n backgroundColor={THEME.panel}\n border\n borderColor={THEME.border}\n flexGrow={1}\n width={sidebarOpen ? tableWidth : \"100%\"}\n onMouseScroll={(event) => {\n if (!event.scroll) {\n return;\n }\n\n const delta = Math.max(1, event.scroll.delta);\n const step = delta * SCROLL_STEP;\n\n if (event.scroll.direction === \"up\") {\n setOffset((current) => Math.max(0, current - step));\n } else if (event.scroll.direction === \"down\") {\n setOffset((current) => {\n const next = current + step;\n return maxOffset === undefined ? next : Math.min(next, maxOffset);\n });\n } else if (event.scroll.direction === \"left\") {\n setXOffset((current) => clampScroll(current - step, maxScrollX));\n } else if (event.scroll.direction === \"right\") {\n setXOffset((current) => clampScroll(current + step, maxScrollX));\n }\n }}\n >\n <text wrapMode=\"none\" truncate fg={THEME.accent}>\n {visibleLines.headerName}\n </text>\n <text wrapMode=\"none\" truncate fg={THEME.muted}>\n {visibleLines.headerType}\n </text>\n <text wrapMode=\"none\" truncate fg={THEME.border}>\n {visibleLines.separator}\n </text>\n {visibleLines.rows.map((line, index) => {\n const isSelected = selection?.row === index;\n return (\n <text\n key={`row-${index}`}\n wrapMode=\"none\"\n truncate\n fg={THEME.text}\n bg={isSelected ? THEME.header : index % 2 === 0 ? THEME.background : THEME.stripe}\n onMouseDown={(event) => {\n const target = event.target;\n if (!target) {\n return;\n }\n const localX = Math.max(0, event.x - target.x);\n const absoluteX = localX + xOffset;\n const colIndex = findColumnIndex(absoluteX, gridLines.columnRanges);\n if (colIndex >= 0) {\n setSelection({ row: index, col: colIndex });\n setSidebarOpen(true);\n }\n }}\n >\n {line}\n </text>\n );\n })}\n </box>\n {sidebarOpen ? (\n <box\n width=\"35%\"\n minWidth={24}\n backgroundColor={THEME.panel}\n border\n borderColor={THEME.border}\n title={detailTitle}\n titleAlignment=\"left\"\n >\n <text wrapMode=\"none\" truncate fg={THEME.muted}>\n press esc/x to close\n </text>\n <scrollbox scrollY flexGrow={1} backgroundColor={THEME.panel}>\n <text\n wrapMode=\"word\"\n fg={THEME.text}\n selectable\n selectionBg={THEME.accent}\n selectionFg={THEME.background}\n >\n {detail}\n </text>\n </scrollbox>\n <text\n wrapMode=\"none\"\n truncate\n fg={THEME.accent}\n onMouseDown={() => {\n setSidebarOpen(false);\n }}\n >\n [ close ]\n </text>\n </box>\n ) : null}\n </box>\n <box backgroundColor={THEME.header} border borderColor={THEME.border}>\n {renderFooter(Boolean(error), notice)}\n </box>\n </box>\n );\n}\n\ntype HeaderProps = {\n filePath: string;\n offset: number;\n rows: number;\n columns: number;\n loading: boolean;\n error: string | null;\n maxRows?: number;\n createdBy?: string;\n optimized: boolean;\n};\n\nfunction renderHeader(props: HeaderProps) {\n const { filePath, offset, rows, columns, loading, error, maxRows, createdBy, optimized } = props;\n\n const start = rows > 0 ? offset + 1 : offset;\n const end = rows > 0 ? offset + rows : offset;\n const totalText = maxRows !== undefined ? `of ${maxRows.toLocaleString()}` : \"\";\n const fileName = filePath.split(\"/\").pop() ?? filePath;\n\n if (error) {\n return (\n <box flexDirection=\"row\" alignItems=\"center\" gap={2} width=\"100%\">\n <text wrapMode=\"none\" fg={THEME.accent}>\n {\"◈ parquetlens\"}\n </text>\n <text wrapMode=\"none\" fg=\"#ef4444\">\n {\"error: \" + error}\n </text>\n </box>\n );\n }\n\n return (\n <box flexDirection=\"row\" alignItems=\"center\" gap={2} width=\"100%\">\n <text wrapMode=\"none\" fg={THEME.accent}>\n {\"◈ parquetlens\"}\n </text>\n <text wrapMode=\"none\" fg={THEME.muted}>\n {\"│\"}\n </text>\n <text wrapMode=\"none\" fg={THEME.text}>\n {fileName}\n </text>\n <text wrapMode=\"none\" fg={THEME.muted}>\n {\"│\"}\n </text>\n <text wrapMode=\"none\" fg={THEME.muted}>\n {\"rows \"}\n </text>\n <text wrapMode=\"none\" fg={THEME.text}>\n {`${start.toLocaleString()}-${end.toLocaleString()} ${totalText}`}\n </text>\n <text wrapMode=\"none\" fg={THEME.muted}>\n {\"│\"}\n </text>\n <text wrapMode=\"none\" fg={THEME.muted}>\n {\"cols \"}\n </text>\n <text wrapMode=\"none\" fg={THEME.text}>\n {columns.toString()}\n </text>\n {createdBy ? (\n <>\n <text wrapMode=\"none\" fg={THEME.muted}>\n {\"│\"}\n </text>\n <text wrapMode=\"none\" fg={THEME.muted} truncate>\n {createdBy}\n </text>\n </>\n ) : null}\n <box flexGrow={1} />\n {loading ? (\n <text wrapMode=\"none\" fg={THEME.badge}>\n {\"● loading\"}\n </text>\n ) : null}\n {optimized ? (\n <text wrapMode=\"none\" fg={THEME.badgeText} bg={THEME.badge}>\n {\" ✓ OPTIMIZED \"}\n </text>\n ) : null}\n </box>\n );\n}\n\nfunction renderFooterLine(hasError: boolean): string {\n const errorHint = hasError ? \" | e view error | y copy error\" : \"\";\n return `q exit | arrows/jk scroll | pgup/pgdn page | h/l col jump | mouse wheel scroll | click cell for detail | s/enter toggle panel${errorHint}`;\n}\n\nfunction renderFooter(hasError: boolean, notice: string | null) {\n const controls = renderFooterLine(hasError);\n\n return (\n <box flexDirection=\"column\" width=\"100%\">\n {notice ? (\n <text wrapMode=\"none\" truncate fg={THEME.badge}>\n {notice}\n </text>\n ) : null}\n <text wrapMode=\"none\" truncate fg={THEME.muted}>\n {controls}\n </text>\n </box>\n );\n}\n\nfunction buildGridLines(grid: GridState, offset: number, targetWidth: number): GridLines {\n const columns: ColumnInfo[] =\n grid.columns.length > 0 ? grid.columns : [{ name: \"(loading)\", type: \"\" }];\n const rows = grid.rows;\n\n const rowNumberWidth = Math.max(String(offset + rows.length).length, 3);\n const columnWidths = columns.map((col, index) => {\n const longestCell = rows.reduce(\n (max, row) => {\n const value = row[index] ?? \"\";\n return Math.max(max, value.length);\n },\n Math.max(col.name.length, col.type.length),\n );\n return Math.min(Math.max(longestCell, DEFAULT_COLUMN_WIDTH), MAX_COLUMN_WIDTH);\n });\n\n const headerNames = [\"#\", ...columns.map((c) => c.name)];\n const headerTypes = [\"\", ...columns.map((c) => c.type)];\n const headerWidths = [rowNumberWidth, ...columnWidths];\n const separatorWidth = headerWidths.length > 1 ? (headerWidths.length - 1) * 2 : 0;\n const baseLength = headerWidths.reduce((total, width) => total + width, 0) + separatorWidth;\n\n if (targetWidth > baseLength && headerWidths.length > 1) {\n headerWidths[headerWidths.length - 1] += targetWidth - baseLength;\n }\n const headerNameLine = buildLine(headerNames, headerWidths);\n const headerTypeLine = buildLine(headerTypes, headerWidths);\n const separatorLine = buildSeparator(headerWidths);\n const rowLines = rows.map((row, index) => {\n const rowIndex = String(offset + index + 1);\n const values = [rowIndex, ...row];\n return buildLine(values, headerWidths);\n });\n\n const { columnRanges, scrollStops } = buildColumnRanges(headerWidths);\n\n const maxLineLength = Math.max(\n headerNameLine.length,\n headerTypeLine.length,\n separatorLine.length,\n ...rowLines.map((line) => line.length),\n );\n\n return {\n headerNameLine,\n headerTypeLine,\n separatorLine,\n rowLines,\n maxLineLength,\n columnRanges,\n scrollStops,\n };\n}\n\nfunction applyHorizontalScroll(\n lines: GridLines,\n width: number,\n xOffset: number,\n pageSize: number,\n): { headerName: string; headerType: string; separator: string; rows: string[] } {\n const sliceLine = (line: string) => {\n if (width <= 0) {\n return \"\";\n }\n const sliced = xOffset <= 0 ? line.slice(0, width) : line.slice(xOffset, xOffset + width);\n return sliced.padEnd(width, \" \");\n };\n\n const rows = lines.rowLines.slice(0, pageSize).map(sliceLine);\n const emptyRow = width > 0 ? \" \".repeat(width) : \"\";\n while (rows.length < pageSize) {\n rows.push(emptyRow);\n }\n\n return {\n headerName: sliceLine(lines.headerNameLine),\n headerType: sliceLine(lines.headerTypeLine),\n separator: sliceLine(lines.separatorLine),\n rows,\n };\n}\n\nfunction buildLine(values: string[], widths: number[]): string {\n return values\n .map((value, index) => {\n const width = widths[index] ?? DEFAULT_COLUMN_WIDTH;\n return padCell(value, width);\n })\n .join(\" \");\n}\n\nfunction buildSeparator(widths: number[]): string {\n return \"\";\n}\n\nfunction padCell(value: string, width: number): string {\n const normalized = normalizeCell(value);\n if (normalized.length > width) {\n if (width <= 3) {\n return normalized.slice(0, width);\n }\n return `${normalized.slice(0, width - 3)}...`;\n }\n return normalized.padEnd(width, \" \");\n}\n\nfunction normalizeCell(value: string): string {\n return value.replace(/\\r?\\n/g, \"\\\\n\").replace(/\\t/g, \"\\\\t\");\n}\n\nfunction buildColumnRanges(widths: number[]): {\n columnRanges: Array<{ start: number; end: number }>;\n scrollStops: number[];\n} {\n const columnRanges: Array<{ start: number; end: number }> = [];\n const scrollStops: number[] = [0];\n let cursor = 0;\n\n for (let i = 0; i < widths.length; i += 1) {\n const width = widths[i];\n if (i > 0) {\n const start = cursor;\n const end = cursor + width - 1;\n columnRanges.push({ start, end });\n scrollStops.push(start);\n }\n cursor += width;\n if (i < widths.length - 1) {\n cursor += 2;\n }\n }\n\n return { columnRanges, scrollStops };\n}\n\nfunction findColumnIndex(x: number, ranges: Array<{ start: number; end: number }>): number {\n for (let index = 0; index < ranges.length; index += 1) {\n const range = ranges[index];\n if (x >= range.start && x <= range.end) {\n return index;\n }\n }\n return -1;\n}\n\nfunction findScrollStop(current: number, stops: number[], direction: 1 | -1): number {\n if (direction > 0) {\n for (const stop of stops) {\n if (stop > current) {\n return stop;\n }\n }\n return current;\n }\n\n for (let index = stops.length - 1; index >= 0; index -= 1) {\n const stop = stops[index];\n if (stop < current) {\n return stop;\n }\n }\n\n return 0;\n}\n\nfunction clampScroll(value: number, max: number): number {\n if (value < 0) {\n return 0;\n }\n if (value > max) {\n return max;\n }\n return value;\n}\n\nfunction buildDetail(\n selection: { row: number; col: number } | null,\n grid: GridState,\n offset: number,\n): string {\n if (!selection || grid.columns.length === 0 || grid.rows.length === 0) {\n return \"click a cell to see full details\";\n }\n\n const rowIndex = Math.min(selection.row, grid.rows.length - 1);\n const colIndex = Math.min(selection.col, grid.columns.length - 1);\n const col = grid.columns[colIndex];\n const columnName = col?.name ?? \"(unknown)\";\n const columnType = col?.type ?? \"\";\n const value = grid.rows[rowIndex]?.[colIndex] ?? \"\";\n const absoluteRow = offset + rowIndex + 1;\n\n return `row ${absoluteRow} • ${columnName}\\n${columnType}\\n\\n${value}`;\n}\n\nfunction buildErrorDetail(message: string): string {\n return `error\\n\\n${message}`;\n}\n\nfunction getMetadataFlags(metadata: ParquetFileMetadata | null): {\n optimized: boolean;\n createdBy?: string;\n} {\n if (!metadata) {\n return { optimized: false };\n }\n\n const raw = metadata.keyValueMetadata[\"content_defined_chunking\"];\n const normalized = raw?.toLowerCase?.() ?? \"\";\n const optimized =\n raw !== undefined && raw !== null && normalized !== \"false\" && normalized !== \"0\";\n\n return {\n optimized,\n createdBy: metadata.createdBy,\n };\n}\n\nfunction tableToRows(table: import(\"apache-arrow\").Table, columns: string[]): string[][] {\n const rows: string[][] = [];\n\n for (const batch of table.batches) {\n const vectors = columns.map((_, index) => batch.getChildAt(index));\n\n for (let rowIndex = 0; rowIndex < batch.numRows; rowIndex += 1) {\n const row = vectors.map((vector) => formatCell(vector?.get(rowIndex)));\n rows.push(row);\n }\n }\n\n return rows;\n}\n\nfunction formatCell(value: unknown): string {\n if (value === null || value === undefined) {\n return \"\";\n }\n\n if (typeof value === \"bigint\") {\n return value.toString();\n }\n\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (value instanceof Uint8Array) {\n return `Uint8Array(${value.length})`;\n }\n\n if (typeof value === \"object\") {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n }\n\n return String(value);\n}\n\nfunction formatArrowType(type: import(\"apache-arrow\").DataType): string {\n return type.toString();\n}\n\nfunction copyToClipboard(value: string): boolean {\n const platform = process.platform;\n const candidates: Array<[string, string[]]> = [];\n\n if (platform === \"darwin\") {\n candidates.push([\"pbcopy\", []]);\n } else if (platform === \"win32\") {\n candidates.push([\"clip\", []]);\n } else {\n candidates.push([\"wl-copy\", []], [\"xclip\", [\"-selection\", \"clipboard\"]]);\n }\n\n for (const [command, args] of candidates) {\n const result = spawnSync(command, args, { input: value });\n if (!result.error && result.status === 0) {\n return true;\n }\n }\n\n return false;\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "parquetlens",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A fast, interactive TUI for viewing Parquet files",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,18 +26,20 @@
|
|
|
26
26
|
"scripts": {
|
|
27
27
|
"dev": "pnpm -C ../../packages/parquet-reader build && tsx src/main.ts",
|
|
28
28
|
"build": "tsup",
|
|
29
|
+
"test": "vitest run",
|
|
29
30
|
"prepublishOnly": "pnpm run build",
|
|
30
31
|
"lint": "tsc -p tsconfig.json --noEmit"
|
|
31
32
|
},
|
|
32
33
|
"dependencies": {
|
|
34
|
+
"@duckdb/duckdb-wasm": "^1.32.0",
|
|
33
35
|
"@opentui/core": "^0.1.74",
|
|
34
36
|
"@opentui/react": "^0.1.74",
|
|
35
|
-
"apache-arrow": "^
|
|
36
|
-
"parquet-wasm": "^0.7.1",
|
|
37
|
+
"apache-arrow": "^17.0.0",
|
|
37
38
|
"react": "^19.2.3"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"@parquetlens/parquet-reader": "workspace:*",
|
|
41
|
-
"@types/react": "^19.2.9"
|
|
42
|
+
"@types/react": "^19.2.9",
|
|
43
|
+
"vitest": "^4.0.18"
|
|
42
44
|
}
|
|
43
45
|
}
|