parquetlens 0.1.0 → 0.2.3

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/main.js CHANGED
@@ -7,12 +7,16 @@ const __filename = fileURLToPath(import.meta.url);
7
7
  const __dirname = dirname(__filename);
8
8
  import {
9
9
  readParquetTableFromPath,
10
- readParquetTableFromStdin
11
- } from "./chunk-573AA4JN.js";
10
+ readParquetTableFromStdin,
11
+ readParquetTableFromUrl,
12
+ resolveParquetUrl
13
+ } from "./chunk-NRRDNC7S.js";
12
14
 
13
15
  // src/main.ts
14
16
  import { spawnSync } from "child_process";
15
17
  import path from "path";
18
+ import { fileURLToPath } from "url";
19
+ var __filename = typeof globalThis.__filename !== "undefined" ? globalThis.__filename : fileURLToPath(import.meta.url);
16
20
  var DEFAULT_LIMIT = 20;
17
21
  function parseArgs(argv) {
18
22
  const options = {
@@ -112,7 +116,7 @@ function readOptionValue(arg, name, next) {
112
116
  return null;
113
117
  }
114
118
  function printUsage() {
115
- const helpText = `parquetlens <file|-> [options]
119
+ const helpText = `parquetlens <file|url|-> [options]
116
120
 
117
121
  options:
118
122
  --limit, --limit=<n> number of rows to show (default: ${DEFAULT_LIMIT})
@@ -127,7 +131,8 @@ options:
127
131
  examples:
128
132
  parquetlens data.parquet --limit 25
129
133
  parquetlens data.parquet --columns=city,state
130
- parquetlens data.parquet --tui
134
+ parquetlens hf://datasets/cfahlgren1/hub-stats/daily_papers.parquet
135
+ parquetlens https://huggingface.co/datasets/cfahlgren1/hub-stats/resolve/main/daily_papers.parquet
131
136
  parquetlens data.parquet --plain
132
137
  parquetlens - < input.parquet
133
138
  `;
@@ -204,11 +209,14 @@ async function loadTable(input, readOptions) {
204
209
  const stdinFallback = process.stdin.isTTY ? void 0 : "-";
205
210
  const source = input ?? stdinFallback;
206
211
  if (!source) {
207
- throw new Error("missing input file (pass a path or pipe stdin)");
212
+ throw new Error("missing input file (pass a path, URL, or pipe stdin)");
208
213
  }
209
214
  if (source === "-") {
210
215
  return readParquetTableFromStdin("stdin.parquet", readOptions);
211
216
  }
217
+ if (resolveParquetUrl(source)) {
218
+ return readParquetTableFromUrl(source, readOptions);
219
+ }
212
220
  return readParquetTableFromPath(source, readOptions);
213
221
  }
214
222
  async function main() {
@@ -227,7 +235,9 @@ async function main() {
227
235
  const wantsTui = resolveTuiMode(options.tuiMode, options);
228
236
  if (wantsTui) {
229
237
  if (!input || input === "-") {
230
- process.stderr.write("parquetlens: tui mode requires a file path (stdin not supported)\n");
238
+ process.stderr.write(
239
+ "parquetlens: tui mode requires a file path or URL (stdin not supported)\n"
240
+ );
231
241
  process.exitCode = 1;
232
242
  return;
233
243
  }
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
- openParquetBufferFromPath
9
- } from "./chunk-573AA4JN.js";
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 { useEffect, useMemo, useState } from "react";
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(filePath, options) {
41
- const source = await openParquetBufferFromPath(filePath);
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: options.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: "cell detail",
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
- return "q exit | arrows/jk scroll | pgup/pgdn page | h/l col jump | mouse wheel scroll | click cell for detail | s/enter toggle panel";
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__ */ jsx("box", { flexDirection: "column", width: "100%", children: /* @__PURE__ */ jsx("text", { wrapMode: "none", truncate: true, fg: THEME.muted, children: controls }) });
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.1.0",
3
+ "version": "0.2.3",
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": "^21.1.0",
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
  }