@sverka/sarif-viewer-tui 0.1.6 → 0.1.8
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/bin.mjs.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/render-D5JdWdKp.mjs.map +1 -1
- package/package.json +2 -2
package/dist/bin.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.mjs","names":[],"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\n// @sverka/sarif-viewer-tui — CLI entry point. Spec 46.\n\nimport process from \"node:process\";\nimport { readFileSync } from \"node:fs\";\nimport { resolveFindings } from \"./input.js\";\n\nasync function main(): Promise<void> {\n const arg = process.argv[2];\n\n if (arg === \"--help\" || arg === \"-h\") {\n process.stdout.write(\n \"Usage: sarif-viewer-tui [file]\\n Reads SARIF from a file argument or stdin.\\n\",\n );\n return;\n }\n\n // Resolve findings first (handles file reading, parsing, normalization).\n // This does NOT import ink — only the render step does.\n let options: { sarifPath: string } | { sarif: unknown } | null;\n if (arg !== undefined) {\n options = { sarifPath: arg };\n } else if (process.stdin.isTTY) {\n options = null;\n } else {\n const raw = readFileSync(0, \"utf8\");\n if (raw.trim() === \"\") {\n process.stderr.write(\"sarif-viewer-tui: stdin is empty.\\n\");\n process.exit(1);\n }\n try {\n options = { sarif: JSON.parse(raw) };\n } catch {\n process.stderr.write(\"sarif-viewer-tui: failed to parse SARIF JSON from stdin.\\n\");\n process.exit(1);\n }\n }\n\n if (options === null) {\n process.stderr.write(\n \"sarif-viewer-tui: no input. Provide a SARIF file argument or pipe SARIF via stdin.\\n\",\n );\n process.exit(1);\n }\n\n const findings = resolveFindings(options);\n\n // Lazy import the render module — this pulls in ink/react, which we only\n // need when actually launching the TUI.\n const { renderSarifTui } = await import(\"./render.js\");\n await renderSarifTui({ findings });\n}\n\ntry {\n await main();\n process.exit(0);\n} catch (e: unknown) {\n process.stderr.write(\n `sarif-viewer-tui: ${e instanceof Error ? e.message : String(e)}\\n`,\n );\n process.exit(1);\n}\n"],"mappings":";;;;;AAOA,eAAe,OAAsB;CACnC,MAAM,MAAM,QAAQ,KAAK;CAEzB,IAAI,QAAQ,YAAY,QAAQ,MAAM;EACpC,QAAQ,OAAO,MACb,gFACF;EACA;CACF;CAIA,IAAI;CACJ,IAAI,QAAQ,KAAA,GACV,UAAU,EAAE,WAAW,IAAI;MACtB,IAAI,QAAQ,MAAM,OACvB,UAAU;MACL;EACL,MAAM,MAAM,aAAa,GAAG,MAAM;EAClC,IAAI,IAAI,KAAK,MAAM,IAAI;GACrB,QAAQ,OAAO,MAAM,qCAAqC;GAC1D,QAAQ,KAAK,CAAC;EAChB;EACA,IAAI;GACF,UAAU,EAAE,OAAO,KAAK,MAAM,GAAG,EAAE;EACrC,QAAQ;GACN,QAAQ,OAAO,
|
|
1
|
+
{"version":3,"file":"bin.mjs","names":[],"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\n// @sverka/sarif-viewer-tui — CLI entry point. Spec 46.\n\nimport process from \"node:process\";\nimport { readFileSync } from \"node:fs\";\nimport { resolveFindings } from \"./input.js\";\n\nasync function main(): Promise<void> {\n const arg = process.argv[2];\n\n if (arg === \"--help\" || arg === \"-h\") {\n process.stdout.write(\n \"Usage: sarif-viewer-tui [file]\\n Reads SARIF from a file argument or stdin.\\n\",\n );\n return;\n }\n\n // Resolve findings first (handles file reading, parsing, normalization).\n // This does NOT import ink — only the render step does.\n let options: { sarifPath: string } | { sarif: unknown } | null;\n if (arg !== undefined) {\n options = { sarifPath: arg };\n } else if (process.stdin.isTTY) {\n options = null;\n } else {\n const raw = readFileSync(0, \"utf8\");\n if (raw.trim() === \"\") {\n process.stderr.write(\"sarif-viewer-tui: stdin is empty.\\n\");\n process.exit(1);\n }\n try {\n options = { sarif: JSON.parse(raw) };\n } catch {\n process.stderr.write(\n \"sarif-viewer-tui: failed to parse SARIF JSON from stdin.\\n\",\n );\n process.exit(1);\n }\n }\n\n if (options === null) {\n process.stderr.write(\n \"sarif-viewer-tui: no input. Provide a SARIF file argument or pipe SARIF via stdin.\\n\",\n );\n process.exit(1);\n }\n\n const findings = resolveFindings(options);\n\n // Lazy import the render module — this pulls in ink/react, which we only\n // need when actually launching the TUI.\n const { renderSarifTui } = await import(\"./render.js\");\n await renderSarifTui({ findings });\n}\n\ntry {\n await main();\n process.exit(0);\n} catch (e: unknown) {\n process.stderr.write(\n `sarif-viewer-tui: ${e instanceof Error ? e.message : String(e)}\\n`,\n );\n process.exit(1);\n}\n"],"mappings":";;;;;AAOA,eAAe,OAAsB;CACnC,MAAM,MAAM,QAAQ,KAAK;CAEzB,IAAI,QAAQ,YAAY,QAAQ,MAAM;EACpC,QAAQ,OAAO,MACb,gFACF;EACA;CACF;CAIA,IAAI;CACJ,IAAI,QAAQ,KAAA,GACV,UAAU,EAAE,WAAW,IAAI;MACtB,IAAI,QAAQ,MAAM,OACvB,UAAU;MACL;EACL,MAAM,MAAM,aAAa,GAAG,MAAM;EAClC,IAAI,IAAI,KAAK,MAAM,IAAI;GACrB,QAAQ,OAAO,MAAM,qCAAqC;GAC1D,QAAQ,KAAK,CAAC;EAChB;EACA,IAAI;GACF,UAAU,EAAE,OAAO,KAAK,MAAM,GAAG,EAAE;EACrC,QAAQ;GACN,QAAQ,OAAO,MACb,4DACF;GACA,QAAQ,KAAK,CAAC;EAChB;CACF;CAEA,IAAI,YAAY,MAAM;EACpB,QAAQ,OAAO,MACb,sFACF;EACA,QAAQ,KAAK,CAAC;CAChB;CAEA,MAAM,WAAW,gBAAgB,OAAO;CAIxC,MAAM,EAAE,mBAAmB,MAAM,OAAO;CACxC,MAAM,eAAe,EAAE,SAAS,CAAC;AACnC;AAEA,IAAI;CACF,MAAM,KAAK;CACX,QAAQ,KAAK,CAAC;AAChB,SAAS,GAAY;CACnB,QAAQ,OAAO,MACb,qBAAqB,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,EAAE,GAClE;CACA,QAAQ,KAAK,CAAC;AAChB"}
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/viewer.tsx","../src/render.ts","../src/filter-model.ts","../src/input.ts"],"mappings":";;;;;UAMiB;;WAEN;;WAEA;;WAEA,oBAAoB;;;WAGpB,UAAU;;;KAIT;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/viewer.tsx","../src/render.ts","../src/filter-model.ts","../src/input.ts"],"mappings":";;;;;UAMiB;;WAEN;;WAEA;;WAEA,oBAAoB;;;WAGpB,UAAU;;;KAIT;;KAIA;;;;qBCJC;WACF,mBAAmB;EAC5B,QAAQ;EACR;EACA;EACA,MAAM;EACN;EACA;UAEQ;mBACS;UACT;EAEI,YAAA,mBAAmB;EAI/B,YAAa;EAOb;EAEA,eAAe;EAIf;EAKA;EAIA,4BAA4B;EAM5B,YAAY,eAAe,KAAK;;;wBAwFlB,YAAY,OAAO;EAAW,mBAAmB;qBAAY,IAAA;;;;;;;;;;;;;;;wBChI7D,eAAe,SAAS,kBAAkB;;;;qBCd7C,2BAA2B;;wBAUxB,aAAa,UAAU;;;wBAiBvB,iBACd,mBAAmB,WACnB,QAAQ,wBACE;;;wBAMI,eACd,mBAAmB,WACnB,yBACU;;;wBAMI,aACd,mBAAmB,WACnB,MAAM,oBACI;;;;;;;;;;;;;;wBC1CI,gBAAgB,SAAS,kBAAkB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-D5JdWdKp.mjs","names":["filterBySeverity","sharedFilterBySeverity","searchFindings","sharedSearchFindings","filterBySeverity","searchFindings"],"sources":["../src/filter-model.ts","../src/viewer.tsx","../src/render.ts"],"sourcesContent":["// @sverka/sarif-viewer-tui — pure filter/search/sort helpers. Spec 46.\n\nimport { filterBySeverity as sharedFilterBySeverity, searchFindings as sharedSearchFindings } from \"@sverka/verification\";\nimport type { Finding, Severity } from \"@sverka/verification\";\nimport type { SortMode, ViewerFilter } from \"./types.js\";\n\n/** Ordered list of severity filters cycled by the `f` key. */\nexport const SEVERITY_FILTERS: readonly ViewerFilter[] = [\n \"all\",\n \"critical\",\n \"high\",\n \"medium\",\n \"low\",\n \"info\",\n];\n\n/** Severity rank for sorting: critical > high > medium > low > info. */\nexport function severityRank(severity: Severity): number {\n switch (severity) {\n case \"critical\":\n return 4;\n case \"high\":\n return 3;\n case \"medium\":\n return 2;\n case \"low\":\n return 1;\n case \"info\":\n return 0;\n }\n}\n\n/** Filter findings by severity level. `all` returns everything. Pure.\n * Delegates to the shared `@sverka/verification` implementation. */\nexport function filterBySeverity(\n findings: readonly Finding[],\n filter: ViewerFilter,\n): readonly Finding[] {\n return sharedFilterBySeverity(findings, filter);\n}\n\n/** Substring match (case-insensitive) across message, checkId, file, rule. Pure.\n * Delegates to the shared `@sverka/verification` implementation. */\nexport function searchFindings(\n findings: readonly Finding[],\n query: string,\n): readonly Finding[] {\n return sharedSearchFindings(findings, query);\n}\n\n/** Sort findings by mode. Sort is stable (preserves original order for equal\n * keys). `none` returns the input unchanged. Pure. */\nexport function sortFindings(\n findings: readonly Finding[],\n mode: SortMode,\n): readonly Finding[] {\n if (mode === \"none\") return findings;\n const indexed = findings.map((f, i) => ({ f, i }));\n switch (mode) {\n case \"severity\":\n indexed.sort(\n (a, b) => severityRank(b.f.severity) - severityRank(a.f.severity) || a.i - b.i,\n );\n break;\n case \"file\":\n indexed.sort(\n (a, b) =>\n a.f.file.localeCompare(b.f.file, \"en\") ||\n a.f.startLine - b.f.startLine ||\n a.i - b.i,\n );\n break;\n case \"rule\":\n indexed.sort(\n (a, b) => a.f.rule.localeCompare(b.f.rule, \"en\") || a.i - b.i,\n );\n break;\n }\n return indexed.map(({ f }) => f);\n}\n","// @sverka/sarif-viewer-tui — Ink TUI component. Spec 46.\n\nimport { useEffect, useRef, useSyncExternalStore } from \"react\";\nimport { Box, Text, useApp, useInput, useStdout } from \"ink\";\nimport type { Key } from \"ink\";\nimport { handleSearchInput, isQuitInput, type Finding } from \"@sverka/verification\";\nimport type { SortMode, ViewerFilter } from \"./types.js\";\nimport {\n SEVERITY_FILTERS,\n filterBySeverity,\n searchFindings,\n sortFindings,\n} from \"./filter-model.js\";\n\n/** Mutable store backing the SarifTuiApp. */\nexport class TuiStore {\n readonly findings: readonly Finding[];\n filter: ViewerFilter = \"all\";\n search = \"\";\n searching = false;\n sort: SortMode = \"none\";\n selected = 0;\n details = false;\n\n private version = 0;\n private readonly listeners = new Set<() => void>();\n private onQuit: (() => void) | null = null;\n\n constructor(findings: readonly Finding[]) {\n this.findings = findings;\n }\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n };\n\n getVersion = (): number => this.version;\n\n setQuitHandler(fn: () => void): void {\n this.onQuit = fn;\n }\n\n notify(): void {\n this.version += 1;\n for (const l of this.listeners) l();\n }\n\n quit(): void {\n this.onQuit?.();\n }\n\n visibleFindings(): readonly Finding[] {\n const filtered = filterBySeverity(this.findings, this.filter);\n const searched = searchFindings(filtered, this.search);\n return sortFindings(searched, this.sort);\n }\n\n handleInput(input: string, key: Key): void {\n if (handleSearchInput(input, key, this)) {\n this.notify();\n return;\n }\n\n if (isQuitInput(input, key)) {\n this.quit();\n return;\n }\n if (input === \"f\") {\n const i = SEVERITY_FILTERS.indexOf(this.filter);\n this.filter = SEVERITY_FILTERS[(i + 1) % SEVERITY_FILTERS.length] ?? \"all\";\n this.selected = Math.min(this.selected, Math.max(0, this.visibleFindings().length - 1));\n } else if (input === \"s\") {\n this.sort = nextSortMode(this.sort);\n this.selected = Math.min(this.selected, Math.max(0, this.visibleFindings().length - 1));\n } else if (input === \"d\") {\n this.details = !this.details;\n } else if (input === \"j\" || key.downArrow) {\n const max = Math.max(0, this.visibleFindings().length - 1);\n this.selected = Math.min(max, this.selected + 1);\n } else if (input === \"k\" || key.upArrow) {\n this.selected = Math.max(0, this.selected - 1);\n } else {\n return;\n }\n this.notify();\n }\n}\n\nconst SORT_CYCLE: readonly SortMode[] = [\"none\", \"severity\", \"file\", \"rule\"];\n\nfunction nextSortMode(mode: SortMode): SortMode {\n const i = SORT_CYCLE.indexOf(mode);\n return SORT_CYCLE[(i + 1) % SORT_CYCLE.length] ?? \"none\";\n}\n\n/** Map a severity to a color prop object. */\nfunction severityColor(severity: string): { color?: string } {\n if (severity === \"critical\" || severity === \"high\") return { color: \"red\" };\n if (severity === \"medium\") return { color: \"yellow\" };\n return {};\n}\n\n/** Render the search indicator based on store state. */\nfunction renderSearchIndicator(store: TuiStore): string {\n if (store.searching) return ` /${store.search}▏`;\n if (store.search) return ` /${store.search}`;\n return \"\";\n}\n\n/** Detail lines for the selected finding. */\nfunction detailsForFinding(finding: Finding): string[] {\n return [\n ` rule: ${finding.rule}`,\n ` file: ${finding.file}`,\n ` lines: ${finding.startLine}–${finding.endLine}`,\n ` message: ${finding.message}`,\n ...(finding.helpUrl ? [` help: ${finding.helpUrl}`] : []),\n ];\n}\n\n/** Compute the viewport window for the visible findings list. */\nfunction computeViewport(\n visible: readonly Finding[],\n selected: number,\n termRows: number,\n detailsCount: number,\n): { start: number; end: number; items: readonly Finding[] } {\n const reservedRows = 4 + detailsCount;\n const maxVisibleRows = Math.max(1, termRows - reservedRows);\n const start = Math.min(\n Math.max(0, selected - Math.floor(maxVisibleRows / 2)),\n Math.max(0, visible.length - maxVisibleRows),\n );\n const end = Math.min(visible.length, start + maxVisibleRows);\n return { start, end, items: visible.slice(start, end) };\n}\n\n/** The standalone SARIF viewer Ink component. */\nexport function SarifTuiApp(props: Readonly<{ findings: readonly Finding[] }>) {\n const storeRef = useRef<TuiStore | null>(null);\n if (storeRef.current === null) {\n storeRef.current = new TuiStore(props.findings);\n }\n const store = storeRef.current;\n useSyncExternalStore(store.subscribe, store.getVersion);\n const { exit } = useApp();\n const { stdout } = useStdout();\n\n useEffect(() => {\n store.setQuitHandler(exit);\n }, [store, exit]);\n\n // Reconcile store when findings prop changes (e.g. hot-reload or re-render\n // with different data). Updates the findings array and clamps selection.\n useEffect(() => {\n if (store.findings !== props.findings) {\n (store as { findings: readonly Finding[] }).findings = props.findings;\n store.selected = Math.min(store.selected, Math.max(0, store.visibleFindings().length - 1));\n store.notify();\n }\n }, [props.findings, store]);\n\n useInput(\n (input, key) => {\n store.handleInput(input, key);\n },\n { isActive: true },\n );\n\n const termCols = stdout.columns || 80;\n const termRows = stdout.rows || 24;\n const maxWidth = Math.max(10, termCols - 2);\n const visible = store.visibleFindings();\n const selected = Math.min(store.selected, Math.max(0, visible.length - 1));\n const selectedFinding = visible[selected];\n\n const detailsLines =\n store.details && selectedFinding ? detailsForFinding(selectedFinding) : [];\n\n const { start: viewportStart, items: viewportItems } = computeViewport(\n visible, selected, termRows, detailsLines.length,\n );\n\n return (\n <Box flexDirection=\"column\">\n <Text bold>SARIF viewer</Text>\n\n <Text>\n {\"Findings \"}\n {SEVERITY_FILTERS.map((f) => (\n <Text key={f} inverse={store.filter === f} bold={store.filter === f}>\n [{f}]\n </Text>\n ))}\n {` (${visible.length})`}\n {renderSearchIndicator(store)}\n </Text>\n\n {visible.length === 0 ? (\n <Text>No findings</Text>\n ) : (\n viewportItems.map((f, i) => {\n const actualIndex = viewportStart + i;\n return (\n <Text\n key={f.id}\n {...(actualIndex === selected ? {} : severityColor(f.severity))}\n inverse={actualIndex === selected}\n wrap=\"truncate\"\n >\n {` ${f.severity.padEnd(8)} ${f.checkId} ${f.file}:${f.startLine} ${f.message}`.slice(\n 0,\n maxWidth,\n )}\n </Text>\n );\n })\n )}\n\n {detailsLines.map((l) => (\n <Text key={`d-${l}`} color=\"gray\" wrap=\"truncate\">\n {l.slice(0, maxWidth)}\n </Text>\n ))}\n\n <Text>\n <Text color=\"gray\">\n q quit · j/k move · / search · f filter · s sort · d details\n </Text>\n </Text>\n </Box>\n );\n}\n","// @sverka/sarif-viewer-tui — render entry point. Spec 46.\n\nimport process from \"node:process\";\nimport { openSync } from \"node:fs\";\nimport { ReadStream } from \"node:tty\";\nimport { render } from \"ink\";\nimport { createElement } from \"react\";\nimport type { Finding } from \"@sverka/verification\";\nimport { resolveFindings } from \"./input.js\";\nimport { SarifTuiApp } from \"./viewer.js\";\nimport type { SarifTuiOptions } from \"./types.js\";\n\n/**\n * Resolve `options` into findings and render the SARIF TUI. Blocks until the\n * user quits (q / Ctrl-C). Resolves on exit.\n *\n * When stdout is not a TTY (piped output, CI, agents) or no interactive\n * input stream is available, Ink cannot run — the findings are printed as\n * plain text instead so the command still produces useful output and exits.\n *\n * Wraps resolveFindings in a try-catch so invalid input produces a clean\n * error message instead of an unhandled synchronous throw before the\n * promise exists.\n */\nexport function renderSarifTui(options: SarifTuiOptions): Promise<void> {\n let findings;\n try {\n findings = resolveFindings(options);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n process.stderr.write(`sarif-viewer-tui: ${msg}\\n`);\n return Promise.resolve();\n }\n\n if (!process.stdout.isTTY || process.env.CI) {\n // Non-interactive stdout or CI — even with a pseudo-TTY there is no\n // user to quit Ink, so a TUI would block forever. Print the findings.\n printFindings(findings);\n return Promise.resolve();\n }\n\n // Ink needs a raw-mode-capable stdin for keyboard input. When SARIF was\n // piped via stdin (e.g. `cat f.sarif | sverka view`), stdin is a pipe —\n // fall back to the controlling terminal so the TUI still works.\n const stdin = interactiveStdin();\n if (stdin === undefined) {\n printFindings(findings);\n return Promise.resolve();\n }\n\n const instance = render(createElement(SarifTuiApp, { findings }), {\n stdout: process.stdout,\n stdin,\n exitOnCtrlC: true,\n });\n return instance.waitUntilExit().then(() => undefined);\n}\n\n/** Return a raw-mode-capable input stream for Ink, or undefined. */\nfunction interactiveStdin(): ReadStream | undefined {\n if (process.stdin.isTTY) return process.stdin;\n // /dev/tty is POSIX-only; on Windows there is no equivalent Node API to\n // reopen console input, so piped stdin degrades to the text fallback.\n if (process.platform === \"win32\") return undefined;\n try {\n return new ReadStream(openSync(\"/dev/tty\", \"r\"));\n } catch {\n // No controlling terminal (CI, detached process) — non-interactive.\n return undefined;\n }\n}\n\n/** Plain-text fallback listing used when the TUI cannot run. */\nfunction printFindings(findings: readonly Finding[]): void {\n process.stdout.write(`SARIF findings (${findings.length}):\\n`);\n for (const f of findings) {\n process.stdout.write(\n ` ${f.severity.padEnd(8)} ${f.checkId} ${f.file}:${f.startLine} ${f.message}\\n`,\n );\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"render-D5JdWdKp.mjs","names":["filterBySeverity","sharedFilterBySeverity","searchFindings","sharedSearchFindings","filterBySeverity","searchFindings"],"sources":["../src/filter-model.ts","../src/viewer.tsx","../src/render.ts"],"sourcesContent":["// @sverka/sarif-viewer-tui — pure filter/search/sort helpers. Spec 46.\n\nimport {\n filterBySeverity as sharedFilterBySeverity,\n searchFindings as sharedSearchFindings,\n} from \"@sverka/verification\";\nimport type { Finding, Severity } from \"@sverka/verification\";\nimport type { SortMode, ViewerFilter } from \"./types.js\";\n\n/** Ordered list of severity filters cycled by the `f` key. */\nexport const SEVERITY_FILTERS: readonly ViewerFilter[] = [\n \"all\",\n \"critical\",\n \"high\",\n \"medium\",\n \"low\",\n \"info\",\n];\n\n/** Severity rank for sorting: critical > high > medium > low > info. */\nexport function severityRank(severity: Severity): number {\n switch (severity) {\n case \"critical\":\n return 4;\n case \"high\":\n return 3;\n case \"medium\":\n return 2;\n case \"low\":\n return 1;\n case \"info\":\n return 0;\n }\n}\n\n/** Filter findings by severity level. `all` returns everything. Pure.\n * Delegates to the shared `@sverka/verification` implementation. */\nexport function filterBySeverity(\n findings: readonly Finding[],\n filter: ViewerFilter,\n): readonly Finding[] {\n return sharedFilterBySeverity(findings, filter);\n}\n\n/** Substring match (case-insensitive) across message, checkId, file, rule. Pure.\n * Delegates to the shared `@sverka/verification` implementation. */\nexport function searchFindings(\n findings: readonly Finding[],\n query: string,\n): readonly Finding[] {\n return sharedSearchFindings(findings, query);\n}\n\n/** Sort findings by mode. Sort is stable (preserves original order for equal\n * keys). `none` returns the input unchanged. Pure. */\nexport function sortFindings(\n findings: readonly Finding[],\n mode: SortMode,\n): readonly Finding[] {\n if (mode === \"none\") return findings;\n const indexed = findings.map((f, i) => ({ f, i }));\n switch (mode) {\n case \"severity\":\n indexed.sort(\n (a, b) =>\n severityRank(b.f.severity) - severityRank(a.f.severity) || a.i - b.i,\n );\n break;\n case \"file\":\n indexed.sort(\n (a, b) =>\n a.f.file.localeCompare(b.f.file, \"en\") ||\n a.f.startLine - b.f.startLine ||\n a.i - b.i,\n );\n break;\n case \"rule\":\n indexed.sort(\n (a, b) => a.f.rule.localeCompare(b.f.rule, \"en\") || a.i - b.i,\n );\n break;\n }\n return indexed.map(({ f }) => f);\n}\n","// @sverka/sarif-viewer-tui — Ink TUI component. Spec 46.\n\nimport { useEffect, useRef, useSyncExternalStore } from \"react\";\nimport { Box, Text, useApp, useInput, useStdout } from \"ink\";\nimport type { Key } from \"ink\";\nimport {\n handleSearchInput,\n isQuitInput,\n type Finding,\n} from \"@sverka/verification\";\nimport type { SortMode, ViewerFilter } from \"./types.js\";\nimport {\n SEVERITY_FILTERS,\n filterBySeverity,\n searchFindings,\n sortFindings,\n} from \"./filter-model.js\";\n\n/** Mutable store backing the SarifTuiApp. */\nexport class TuiStore {\n readonly findings: readonly Finding[];\n filter: ViewerFilter = \"all\";\n search = \"\";\n searching = false;\n sort: SortMode = \"none\";\n selected = 0;\n details = false;\n\n private version = 0;\n private readonly listeners = new Set<() => void>();\n private onQuit: (() => void) | null = null;\n\n constructor(findings: readonly Finding[]) {\n this.findings = findings;\n }\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n };\n\n getVersion = (): number => this.version;\n\n setQuitHandler(fn: () => void): void {\n this.onQuit = fn;\n }\n\n notify(): void {\n this.version += 1;\n for (const l of this.listeners) l();\n }\n\n quit(): void {\n this.onQuit?.();\n }\n\n visibleFindings(): readonly Finding[] {\n const filtered = filterBySeverity(this.findings, this.filter);\n const searched = searchFindings(filtered, this.search);\n return sortFindings(searched, this.sort);\n }\n\n handleInput(input: string, key: Key): void {\n if (handleSearchInput(input, key, this)) {\n this.notify();\n return;\n }\n\n if (isQuitInput(input, key)) {\n this.quit();\n return;\n }\n if (input === \"f\") {\n const i = SEVERITY_FILTERS.indexOf(this.filter);\n this.filter =\n SEVERITY_FILTERS[(i + 1) % SEVERITY_FILTERS.length] ?? \"all\";\n this.selected = Math.min(\n this.selected,\n Math.max(0, this.visibleFindings().length - 1),\n );\n } else if (input === \"s\") {\n this.sort = nextSortMode(this.sort);\n this.selected = Math.min(\n this.selected,\n Math.max(0, this.visibleFindings().length - 1),\n );\n } else if (input === \"d\") {\n this.details = !this.details;\n } else if (input === \"j\" || key.downArrow) {\n const max = Math.max(0, this.visibleFindings().length - 1);\n this.selected = Math.min(max, this.selected + 1);\n } else if (input === \"k\" || key.upArrow) {\n this.selected = Math.max(0, this.selected - 1);\n } else {\n return;\n }\n this.notify();\n }\n}\n\nconst SORT_CYCLE: readonly SortMode[] = [\"none\", \"severity\", \"file\", \"rule\"];\n\nfunction nextSortMode(mode: SortMode): SortMode {\n const i = SORT_CYCLE.indexOf(mode);\n return SORT_CYCLE[(i + 1) % SORT_CYCLE.length] ?? \"none\";\n}\n\n/** Map a severity to a color prop object. */\nfunction severityColor(severity: string): { color?: string } {\n if (severity === \"critical\" || severity === \"high\") return { color: \"red\" };\n if (severity === \"medium\") return { color: \"yellow\" };\n return {};\n}\n\n/** Render the search indicator based on store state. */\nfunction renderSearchIndicator(store: TuiStore): string {\n if (store.searching) return ` /${store.search}▏`;\n if (store.search) return ` /${store.search}`;\n return \"\";\n}\n\n/** Detail lines for the selected finding. */\nfunction detailsForFinding(finding: Finding): string[] {\n return [\n ` rule: ${finding.rule}`,\n ` file: ${finding.file}`,\n ` lines: ${finding.startLine}–${finding.endLine}`,\n ` message: ${finding.message}`,\n ...(finding.helpUrl ? [` help: ${finding.helpUrl}`] : []),\n ];\n}\n\n/** Compute the viewport window for the visible findings list. */\nfunction computeViewport(\n visible: readonly Finding[],\n selected: number,\n termRows: number,\n detailsCount: number,\n): { start: number; end: number; items: readonly Finding[] } {\n const reservedRows = 4 + detailsCount;\n const maxVisibleRows = Math.max(1, termRows - reservedRows);\n const start = Math.min(\n Math.max(0, selected - Math.floor(maxVisibleRows / 2)),\n Math.max(0, visible.length - maxVisibleRows),\n );\n const end = Math.min(visible.length, start + maxVisibleRows);\n return { start, end, items: visible.slice(start, end) };\n}\n\n/** The standalone SARIF viewer Ink component. */\nexport function SarifTuiApp(props: Readonly<{ findings: readonly Finding[] }>) {\n const storeRef = useRef<TuiStore | null>(null);\n if (storeRef.current === null) {\n storeRef.current = new TuiStore(props.findings);\n }\n const store = storeRef.current;\n useSyncExternalStore(store.subscribe, store.getVersion);\n const { exit } = useApp();\n const { stdout } = useStdout();\n\n useEffect(() => {\n store.setQuitHandler(exit);\n }, [store, exit]);\n\n // Reconcile store when findings prop changes (e.g. hot-reload or re-render\n // with different data). Updates the findings array and clamps selection.\n useEffect(() => {\n if (store.findings !== props.findings) {\n (store as { findings: readonly Finding[] }).findings = props.findings;\n store.selected = Math.min(\n store.selected,\n Math.max(0, store.visibleFindings().length - 1),\n );\n store.notify();\n }\n }, [props.findings, store]);\n\n useInput(\n (input, key) => {\n store.handleInput(input, key);\n },\n { isActive: true },\n );\n\n const termCols = stdout.columns || 80;\n const termRows = stdout.rows || 24;\n const maxWidth = Math.max(10, termCols - 2);\n const visible = store.visibleFindings();\n const selected = Math.min(store.selected, Math.max(0, visible.length - 1));\n const selectedFinding = visible[selected];\n\n const detailsLines =\n store.details && selectedFinding ? detailsForFinding(selectedFinding) : [];\n\n const { start: viewportStart, items: viewportItems } = computeViewport(\n visible,\n selected,\n termRows,\n detailsLines.length,\n );\n\n return (\n <Box flexDirection=\"column\">\n <Text bold>SARIF viewer</Text>\n\n <Text>\n {\"Findings \"}\n {SEVERITY_FILTERS.map((f) => (\n <Text key={f} inverse={store.filter === f} bold={store.filter === f}>\n [{f}]\n </Text>\n ))}\n {` (${visible.length})`}\n {renderSearchIndicator(store)}\n </Text>\n\n {visible.length === 0 ? (\n <Text>No findings</Text>\n ) : (\n viewportItems.map((f, i) => {\n const actualIndex = viewportStart + i;\n return (\n <Text\n key={f.id}\n {...(actualIndex === selected ? {} : severityColor(f.severity))}\n inverse={actualIndex === selected}\n wrap=\"truncate\"\n >\n {` ${f.severity.padEnd(8)} ${f.checkId} ${f.file}:${f.startLine} ${f.message}`.slice(\n 0,\n maxWidth,\n )}\n </Text>\n );\n })\n )}\n\n {detailsLines.map((l) => (\n <Text key={`d-${l}`} color=\"gray\" wrap=\"truncate\">\n {l.slice(0, maxWidth)}\n </Text>\n ))}\n\n <Text>\n <Text color=\"gray\">\n q quit · j/k move · / search · f filter · s sort · d details\n </Text>\n </Text>\n </Box>\n );\n}\n","// @sverka/sarif-viewer-tui — render entry point. Spec 46.\n\nimport process from \"node:process\";\nimport { openSync } from \"node:fs\";\nimport { ReadStream } from \"node:tty\";\nimport { render } from \"ink\";\nimport { createElement } from \"react\";\nimport type { Finding } from \"@sverka/verification\";\nimport { resolveFindings } from \"./input.js\";\nimport { SarifTuiApp } from \"./viewer.js\";\nimport type { SarifTuiOptions } from \"./types.js\";\n\n/**\n * Resolve `options` into findings and render the SARIF TUI. Blocks until the\n * user quits (q / Ctrl-C). Resolves on exit.\n *\n * When stdout is not a TTY (piped output, CI, agents) or no interactive\n * input stream is available, Ink cannot run — the findings are printed as\n * plain text instead so the command still produces useful output and exits.\n *\n * Wraps resolveFindings in a try-catch so invalid input produces a clean\n * error message instead of an unhandled synchronous throw before the\n * promise exists.\n */\nexport function renderSarifTui(options: SarifTuiOptions): Promise<void> {\n let findings;\n try {\n findings = resolveFindings(options);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n process.stderr.write(`sarif-viewer-tui: ${msg}\\n`);\n return Promise.resolve();\n }\n\n if (!process.stdout.isTTY || process.env.CI) {\n // Non-interactive stdout or CI — even with a pseudo-TTY there is no\n // user to quit Ink, so a TUI would block forever. Print the findings.\n printFindings(findings);\n return Promise.resolve();\n }\n\n // Ink needs a raw-mode-capable stdin for keyboard input. When SARIF was\n // piped via stdin (e.g. `cat f.sarif | sverka view`), stdin is a pipe —\n // fall back to the controlling terminal so the TUI still works.\n const stdin = interactiveStdin();\n if (stdin === undefined) {\n printFindings(findings);\n return Promise.resolve();\n }\n\n const instance = render(createElement(SarifTuiApp, { findings }), {\n stdout: process.stdout,\n stdin,\n exitOnCtrlC: true,\n });\n return instance.waitUntilExit().then(() => undefined);\n}\n\n/** Return a raw-mode-capable input stream for Ink, or undefined. */\nfunction interactiveStdin(): ReadStream | undefined {\n if (process.stdin.isTTY) return process.stdin;\n // /dev/tty is POSIX-only; on Windows there is no equivalent Node API to\n // reopen console input, so piped stdin degrades to the text fallback.\n if (process.platform === \"win32\") return undefined;\n try {\n return new ReadStream(openSync(\"/dev/tty\", \"r\"));\n } catch {\n // No controlling terminal (CI, detached process) — non-interactive.\n return undefined;\n }\n}\n\n/** Plain-text fallback listing used when the TUI cannot run. */\nfunction printFindings(findings: readonly Finding[]): void {\n process.stdout.write(`SARIF findings (${findings.length}):\\n`);\n for (const f of findings) {\n process.stdout.write(\n ` ${f.severity.padEnd(8)} ${f.checkId} ${f.file}:${f.startLine} ${f.message}\\n`,\n );\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sverka/sarif-viewer-tui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Sverka SARIF viewer TUI — standalone Ink-based terminal viewer for SARIF files",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"react": ">=19.2.0 <20"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@sverka/verification": "^0.1.
|
|
43
|
+
"@sverka/verification": "^0.1.8"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/react": "^19",
|