@squadbase/vantage 0.6.2-dev1.9d91dda → 0.6.2-dev1.ac99e02
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/add-4GHF2TX2.js +6 -0
- package/dist/add-4GHF2TX2.js.map +1 -0
- package/dist/{build-TVKFIVFQ.js → build-MFWRPYKW.js} +7 -7
- package/dist/{build-TVKFIVFQ.js.map → build-MFWRPYKW.js.map} +1 -1
- package/dist/{check-3KHZXZMQ.js → check-ZBIH422T.js} +5 -5
- package/dist/{check-3KHZXZMQ.js.map → check-ZBIH422T.js.map} +1 -1
- package/dist/{chunk-P7W4LR3Z.js → chunk-7DZGJQ3P.js} +3 -3
- package/dist/{chunk-P7W4LR3Z.js.map → chunk-7DZGJQ3P.js.map} +1 -1
- package/dist/{chunk-U2M6HGKQ.js → chunk-AABMKHEU.js} +4 -4
- package/dist/{chunk-U2M6HGKQ.js.map → chunk-AABMKHEU.js.map} +1 -1
- package/dist/{chunk-NKFBFDRZ.js → chunk-AG6RZ2RR.js} +981 -14
- package/dist/chunk-AG6RZ2RR.js.map +1 -0
- package/dist/{chunk-QI3XQKHS.js → chunk-GNXCX4WE.js} +10 -3
- package/dist/chunk-GNXCX4WE.js.map +1 -0
- package/dist/chunk-IBGOCWJB.js +1716 -0
- package/dist/chunk-IBGOCWJB.js.map +1 -0
- package/dist/{chunk-RPZAALCX.js → chunk-OB6UBJXF.js} +153 -153
- package/dist/{chunk-RPZAALCX.js.map → chunk-OB6UBJXF.js.map} +1 -1
- package/dist/{chunk-LMUACBMA.js → chunk-QEWCYW3I.js} +43 -8
- package/dist/chunk-QEWCYW3I.js.map +1 -0
- package/dist/{chunk-ZVANIULZ.js → chunk-RNTDBX6S.js} +4 -4
- package/dist/{chunk-ZVANIULZ.js.map → chunk-RNTDBX6S.js.map} +1 -1
- package/dist/{chunk-PVTHHV7X.js → chunk-V3LF7BE7.js} +27 -5
- package/dist/chunk-V3LF7BE7.js.map +1 -0
- package/dist/{chunk-DTDVSFRY.js → chunk-XQUSGIDG.js} +17 -3
- package/dist/chunk-XQUSGIDG.js.map +1 -0
- package/dist/cli.js +12 -11
- package/dist/cli.js.map +1 -1
- package/dist/client/index.d.ts +32 -3
- package/dist/client/index.js +205 -12
- package/dist/client/index.js.map +1 -1
- package/dist/components/index.d.ts +216 -1
- package/dist/components/index.js +2 -2
- package/dist/{dev-GDKATCC7.js → dev-DCTOHQ6W.js} +8 -8
- package/dist/dev-DCTOHQ6W.js.map +1 -0
- package/dist/{docs-EJJ3BECT.js → docs-JVP4RPKT.js} +3 -3
- package/dist/{docs-EJJ3BECT.js.map → docs-JVP4RPKT.js.map} +1 -1
- package/dist/{doctor-WQXPXP6K.js → doctor-5E2VEZPK.js} +5 -5
- package/dist/{doctor-WQXPXP6K.js.map → doctor-5E2VEZPK.js.map} +1 -1
- package/dist/{preview-OGMCNQUO.js → preview-T6CLSQVX.js} +3 -3
- package/dist/{preview-OGMCNQUO.js.map → preview-T6CLSQVX.js.map} +1 -1
- package/dist/query/index.d.ts +0 -11
- package/dist/query/index.js +2 -2
- package/dist/{routes-MWBWWOJ2.js → routes-3SGAFDMC.js} +4 -4
- package/dist/{routes-MWBWWOJ2.js.map → routes-3SGAFDMC.js.map} +1 -1
- package/dist/{search-6Y422SV6.js → search-5LC4XPB5.js} +3 -3
- package/dist/{search-6Y422SV6.js.map → search-5LC4XPB5.js.map} +1 -1
- package/dist/table/index.js +7 -6
- package/dist/table/index.js.map +1 -1
- package/dist/ui/index.d.ts +140 -10
- package/dist/ui/index.js +1405 -63
- package/dist/ui/index.js.map +1 -1
- package/dist/{upgrade-HCANX4GQ.js → upgrade-DBBE6GIR.js} +6 -6
- package/dist/{upgrade-HCANX4GQ.js.map → upgrade-DBBE6GIR.js.map} +1 -1
- package/dist/vite/index.d.ts +10 -0
- package/dist/vite/index.js +3 -3
- package/docs/index.json +291 -61
- package/docs/ja/changelog.md +26 -0
- package/docs/ja/components.md +33 -89
- package/docs/ja/page-types/csv.md +83 -0
- package/docs/ja/page-types/doc.md +83 -0
- package/docs/ja/page-types/excel.md +82 -0
- package/docs/ja/page-types/slide.md +132 -0
- package/docs/ja/page-types.md +47 -0
- package/docs/ja/parts/area-chart.md +61 -0
- package/docs/ja/parts/bar-chart.md +69 -0
- package/docs/ja/parts/bar-list.md +35 -0
- package/docs/ja/parts/category-bar.md +36 -0
- package/docs/ja/parts/donut-chart.md +47 -0
- package/docs/ja/parts/echart.md +3 -0
- package/docs/ja/parts/line-chart.md +58 -0
- package/docs/ja/parts/progress-circle.md +34 -0
- package/docs/ja/parts/sparkline.md +1 -1
- package/docs/ja/parts/tracker.md +32 -0
- package/docs/ja/routing.md +8 -86
- package/docs/ja/ui/alert-dialog.md +41 -0
- package/docs/ja/ui/avatar.md +31 -0
- package/docs/ja/ui/combobox.md +74 -0
- package/docs/ja/ui/drawer.md +41 -0
- package/docs/ja/ui/field.md +42 -0
- package/docs/ja/ui/hover-card.md +21 -0
- package/docs/ja/ui/kbd.md +16 -0
- package/docs/ja/ui/pagination.md +36 -0
- package/docs/ja/ui/radio-group.md +21 -0
- package/docs/ja/ui/toast.md +46 -0
- package/docs/ja/ui-and-theming.md +14 -7
- package/package.json +21 -13
- package/registry/ui/accordion.tsx +74 -0
- package/registry/ui/alert-dialog.tsx +189 -0
- package/registry/ui/alert.tsx +78 -0
- package/registry/ui/app-shell.tsx +281 -0
- package/registry/ui/area-chart.tsx +1015 -0
- package/registry/ui/avatar.tsx +110 -0
- package/registry/ui/badge.tsx +54 -0
- package/registry/ui/bar-chart.tsx +1013 -0
- package/registry/ui/bar-list.tsx +302 -0
- package/registry/ui/breadcrumb.tsx +126 -0
- package/registry/ui/button.tsx +60 -0
- package/registry/ui/calendar.tsx +221 -0
- package/registry/ui/card.tsx +105 -0
- package/registry/ui/category-bar.tsx +281 -0
- package/registry/ui/checkbox.tsx +28 -0
- package/registry/ui/collapsible.tsx +21 -0
- package/registry/ui/combobox.tsx +310 -0
- package/registry/ui/command.tsx +196 -0
- package/registry/ui/dashboard-card.tsx +174 -0
- package/registry/ui/data-table.tsx +16 -91
- package/registry/ui/date-range-picker.tsx +209 -0
- package/registry/ui/dialog.tsx +159 -0
- package/registry/ui/donut-chart.tsx +1004 -0
- package/registry/ui/drawer.tsx +229 -0
- package/registry/ui/dropdown-menu.tsx +272 -0
- package/registry/ui/echart.tsx +486 -0
- package/registry/ui/field.tsx +240 -0
- package/registry/ui/filter-bar.tsx +365 -0
- package/registry/ui/funnel-steps.tsx +274 -0
- package/registry/ui/hover-card.tsx +52 -0
- package/registry/ui/input-group.tsx +158 -0
- package/registry/ui/input.tsx +22 -0
- package/registry/ui/kbd.tsx +28 -0
- package/registry/ui/label.tsx +20 -0
- package/registry/ui/line-chart.tsx +1007 -0
- package/registry/ui/metric-value.tsx +54 -0
- package/registry/ui/multi-select.tsx +226 -0
- package/registry/ui/page-shell.tsx +227 -0
- package/registry/ui/pagination.tsx +138 -0
- package/registry/ui/placeholder.tsx +30 -0
- package/registry/ui/popover.tsx +90 -0
- package/registry/ui/progress-circle.tsx +272 -0
- package/registry/ui/progress.tsx +83 -0
- package/registry/ui/radio-group.tsx +39 -0
- package/registry/ui/scroll-area.tsx +55 -0
- package/registry/ui/searchable-select.tsx +209 -0
- package/registry/ui/section-header.tsx +41 -0
- package/registry/ui/segmented-control.tsx +71 -0
- package/registry/ui/select.tsx +253 -0
- package/registry/ui/separator.tsx +25 -0
- package/registry/ui/sheet.tsx +137 -0
- package/registry/ui/sidebar.tsx +723 -0
- package/registry/ui/skeleton.tsx +15 -0
- package/registry/ui/slider.tsx +54 -0
- package/registry/ui/sparkline.tsx +155 -0
- package/registry/ui/spinner.tsx +12 -0
- package/registry/ui/states.tsx +61 -0
- package/registry/ui/status-badge.tsx +79 -0
- package/registry/ui/switch.tsx +32 -0
- package/registry/ui/table.tsx +116 -0
- package/registry/ui/tabs.tsx +82 -0
- package/registry/ui/textarea.tsx +20 -0
- package/registry/ui/toast.tsx +250 -0
- package/registry/ui/toggle-group.tsx +89 -0
- package/registry/ui/toggle.tsx +45 -0
- package/registry/ui/tooltip.tsx +66 -0
- package/registry/ui/tracker.tsx +236 -0
- package/registry/ui/trend-indicator.tsx +62 -0
- package/skills/vantage-add-feature/SKILL.md +9 -7
- package/skills/vantage-pitfalls/SKILL.md +5 -1
- package/templates/AGENTS.md +10 -1
- package/templates/agents/csv.md +2 -1
- package/templates/agents/doc.md +4 -3
- package/templates/agents/page.md +22 -8
- package/templates/agents/xlsx.md +2 -1
- package/dist/add-DY4AXANK.js +0 -6
- package/dist/add-DY4AXANK.js.map +0 -1
- package/dist/chunk-DTDVSFRY.js.map +0 -1
- package/dist/chunk-LMUACBMA.js.map +0 -1
- package/dist/chunk-NKFBFDRZ.js.map +0 -1
- package/dist/chunk-PVTHHV7X.js.map +0 -1
- package/dist/chunk-QI3XQKHS.js.map +0 -1
- package/dist/chunk-VA776YE5.js +0 -316
- package/dist/chunk-VA776YE5.js.map +0 -1
- package/dist/dev-GDKATCC7.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/search-index.ts","../src/cli/search.ts"],"names":[],"mappings":"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","file":"search-6Y422SV6.js","sourcesContent":["import { readDoc, type DocEntry } from \"./docs-catalog\"\n\n/**\n * A tiny BM25F ranker over the bundled documentation. The corpus is the catalog\n * `docs-catalog.ts` exposes — the same one `vantage docs` prints, so search never\n * creates a second source of truth.\n *\n * The index is built at run time: 65 pages per language (~300 KB) tokenize in a\n * few milliseconds, which is cheaper than shipping and version-locking a\n * prebuilt index alongside the docs bundle.\n */\n\n/**\n * Field weights. A name or a title match says far more about relevance than one\n * more occurrence in a long body, and BM25F models that as a weighted term\n * frequency (and a matching weighted document length).\n */\nconst FIELD_WEIGHTS = { slug: 3, title: 3, description: 2, body: 1 } as const\n\n/** Standard BM25 constants: term-frequency saturation and length normalization. */\nconst K1 = 1.2\nconst B = 0.75\n\n/**\n * Latin/digit runs, or runs of Japanese script (kana + CJK ideographs). CJK\n * punctuation (U+3000–U+303F, 。and 、) is deliberately outside the ranges, so\n * runs break at sentence boundaries.\n */\nconst TOKEN_RE = /[a-z0-9]+|[-ヿ㐀-䶿一-鿿]+/g\nconst LATIN_RE = /^[a-z0-9]+$/\n/** `TOKEN_RE`, but before lowercasing — for text that is not being indexed. */\nconst TOKEN_RE_ANYCASE = /[a-zA-Z0-9]+|[-ヿ㐀-䶿一-鿿]+/g\nconst CJK_RE = /[-ヿ㐀-䶿一-鿿]/\n\n/**\n * One run of a single script: hiragana (U+3041–U+309F), katakana (U+30A0–U+30FF,\n * so ー stays inside テーブル), or kanji. Japanese writes content words in\n * katakana and kanji and the grammatical glue between them in hiragana, so\n * cutting at every script change segments 「テーブルにページングを付けたい」into\n * テーブル · に · ページング · を · 付 · けたい without a morphological analyser.\n */\nconst SCRIPT_RE = /[ぁ-ゟ]+|[゠-ヿ]+|[㐀-䶿一-鿿]+/g\nconst HIRAGANA_RE = /^[ぁ-ゟ]$/\n\n/** Plural forms, so `colors` finds `color` and `queries` finds `query`. */\nfunction singular(word: string): string {\n if (word.length >= 5 && word.endsWith(\"ies\")) return `${word.slice(0, -3)}y`\n if (word.length >= 4 && word.endsWith(\"s\") && !/(ss|us|is)$/.test(word)) return word.slice(0, -1)\n return word\n}\n\n/**\n * Split text into index terms. Latin runs become words (`DataTable` splits into\n * `data` + `table`, so a two-word query finds it). Japanese runs are segmented\n * by script change; each segment is indexed whole *and* as character bigrams,\n * so an exact word scores high while a near miss (ページング / ページネーション)\n * still shares enough terms to be found.\n */\nexport function tokenize(text: string): string[] {\n const normalized = text\n .normalize(\"NFKC\")\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .toLowerCase()\n const tokens: string[] = []\n for (const match of normalized.matchAll(TOKEN_RE)) {\n const run = match[0]!\n if (LATIN_RE.test(run)) {\n tokens.push(singular(run))\n continue\n }\n for (const segment of run.match(SCRIPT_RE) ?? []) {\n // A lone hiragana is a particle (を, に, が …): it appears in every page\n // and would make every page a match.\n if (segment.length === 1 && HIRAGANA_RE.test(segment)) continue\n // A 2-character segment is its own only bigram — pushing both would\n // double-count it.\n if (segment.length <= 2) {\n tokens.push(segment)\n continue\n }\n tokens.push(segment)\n for (let i = 0; i < segment.length - 1; i++) tokens.push(segment.slice(i, i + 2))\n }\n }\n return tokens\n}\n\n/**\n * The words a snippet should highlight: whole words and whole Japanese\n * segments as the user typed them, without the derived bigrams (highlighting\n * those would paint most of a Japanese line yellow) and without the singular\n * rewrite (which no longer appears verbatim in the text).\n */\nexport function queryPhrases(query: string): string[] {\n const phrases: string[] = []\n for (const match of query.normalize(\"NFKC\").matchAll(TOKEN_RE_ANYCASE)) {\n const run = match[0]!\n if (!CJK_RE.test(run)) {\n phrases.push(run)\n continue\n }\n for (const segment of run.match(SCRIPT_RE) ?? []) {\n if (segment.length === 1 && HIRAGANA_RE.test(segment)) continue\n phrases.push(segment)\n }\n }\n return [...new Set(phrases)]\n}\n\n/** One ranked document, with the body kept for snippet extraction. */\nexport interface SearchHit {\n entry: DocEntry\n score: number\n /** Query terms that were looked up — the input for `snippet()`. */\n terms: string[]\n body: string\n}\n\ninterface IndexedDoc {\n entry: DocEntry\n body: string\n /** Weighted term frequency across all fields. */\n tf: Map<string, number>\n /** Weighted document length. */\n length: number\n}\n\nexport interface SearchIndex {\n /** Every document with a non-zero score, best first. */\n search(query: string): SearchHit[]\n}\n\n/** Build the index for one language's catalog entries. */\nexport function buildIndex(entries: DocEntry[]): SearchIndex {\n const docs: IndexedDoc[] = entries.map((entry) => {\n const body = readDoc(entry)\n const tf = new Map<string, number>()\n let length = 0\n const add = (text: string, weight: number) => {\n for (const token of tokenize(text)) {\n tf.set(token, (tf.get(token) ?? 0) + weight)\n length += weight\n }\n }\n add(entry.slug, FIELD_WEIGHTS.slug)\n add(entry.title, FIELD_WEIGHTS.title)\n add(entry.description, FIELD_WEIGHTS.description)\n add(body, FIELD_WEIGHTS.body)\n return { entry, body, tf, length }\n })\n\n const df = new Map<string, number>()\n for (const doc of docs) {\n for (const term of doc.tf.keys()) df.set(term, (df.get(term) ?? 0) + 1)\n }\n const total = docs.length\n const avgLength = total ? docs.reduce((sum, doc) => sum + doc.length, 0) / total : 1\n\n return {\n search(query: string): SearchHit[] {\n const terms = [...new Set(tokenize(query))]\n if (terms.length === 0) return []\n\n const hits: SearchHit[] = []\n for (const doc of docs) {\n let score = 0\n for (const term of terms) {\n const tf = doc.tf.get(term)\n if (!tf) continue\n const n = df.get(term) ?? 0\n const idf = Math.log(1 + (total - n + 0.5) / (n + 0.5))\n const norm = 1 - B + (B * doc.length) / avgLength\n score += idf * ((tf * (K1 + 1)) / (tf + K1 * norm))\n }\n if (score > 0) hits.push({ entry: doc.entry, score, terms, body: doc.body })\n }\n hits.sort((a, b) => b.score - a.score || a.entry.slug.localeCompare(b.entry.slug))\n return hits\n },\n }\n}\n\n/** How much of a line to show around the first matched term. */\nconst SNIPPET_LENGTH = 150\n\n/**\n * Pick the passage that best covers the query terms. Lines are compared\n * lowercased only (no NFKC, no camelCase splitting) so offsets stay aligned\n * with the text that is printed.\n */\nexport function snippet(body: string, terms: string[], length = SNIPPET_LENGTH): string {\n let best = \"\"\n let bestHits = 0\n let bestIndex = 0\n let bestIsHeading = true\n\n // The first line is the page's own `# Title`, which the caller already shows.\n for (const raw of body.split(\"\\n\").slice(1)) {\n const line = raw.replace(/^\\s*[-*]\\s+/, \"\").replace(/\\s+/g, \" \").trim()\n if (!line || /^(```|~~~|\\|\\s*-{2,})/.test(line)) continue\n const haystack = line.toLowerCase()\n const heading = line.startsWith(\"#\")\n let hits = 0\n let first = -1\n for (const term of terms) {\n const at = haystack.indexOf(term)\n if (at === -1) continue\n hits++\n if (first === -1 || at < first) first = at\n }\n // Equal coverage: prose says more than a heading does.\n if (hits > bestHits || (hits === bestHits && hits > 0 && bestIsHeading && !heading)) {\n best = line\n bestHits = hits\n bestIndex = first\n bestIsHeading = heading\n }\n }\n\n if (!bestHits) return \"\"\n if (best.length <= length) return best\n\n const start = Math.max(0, bestIndex - Math.floor(length / 4))\n const text = best.slice(start, start + length).trim()\n return `${start > 0 ? \"…\" : \"\"}${text}${start + length < best.length ? \"…\" : \"\"}`\n}\n","import pc from \"picocolors\"\nimport {\n DEFAULT_DOC_LANG,\n DOC_LANGS,\n docsForLang,\n isDocLang,\n loadCatalog,\n readDoc,\n type DocEntry,\n type DocLang,\n} from \"./docs-catalog\"\nimport { buildIndex, queryPhrases, snippet, type SearchHit } from \"./search-index\"\nimport { log, printJson, type ParsedArgs } from \"./util\"\n\n/** Results shown when `--limit` is absent. */\nconst DEFAULT_LIMIT = 10\n\n/** Matching lines printed per page in regex mode (the count is always exact). */\nconst MAX_REGEX_LINES = 3\n\n/** Parse `--limit`, falling back silently — an off result list is not a failure. */\nfunction parseLimit(value: string | boolean | undefined, fallback: number): number {\n if (typeof value === \"string\") {\n const n = Number(value)\n if (Number.isInteger(n) && n > 0) return n\n }\n return fallback\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n}\n\n/** Dim a line, with every match of `re` picked out. Piped output stays plain. */\nfunction paintMatches(text: string, re: RegExp): string {\n if (!process.stdout.isTTY) return text\n let out = \"\"\n let last = 0\n for (const match of text.matchAll(re)) {\n const at = match.index ?? 0\n if (!match[0]) continue // zero-length match: nothing to highlight\n out += pc.dim(text.slice(last, at)) + pc.yellow(match[0])\n last = at + match[0].length\n }\n return out + pc.dim(text.slice(last))\n}\n\n/** Same, for the words of a natural-language query. */\nfunction paintTerms(text: string, words: string[]): string {\n if (!process.stdout.isTTY) return text\n if (words.length === 0) return pc.dim(text)\n return paintMatches(text, new RegExp(words.map(escapeRegExp).join(\"|\"), \"gi\"))\n}\n\nfunction header(count: number, query: string, lang: DocLang, mode: string): void {\n const label = `${count} result${count === 1 ? \"\" : \"s\"} for \"${query}\"`\n console.log(\"\")\n console.log(pc.bold(label) + pc.dim(` ${lang} · ${mode}`))\n console.log(\"\")\n}\n\nfunction footer(total: number, shown: number, lines: string[]): void {\n if (total > shown) {\n console.log(\"\")\n console.log(pc.dim(` ${total - shown} more — raise --limit to see them`))\n }\n console.log(\"\")\n for (const line of lines) console.log(pc.dim(line))\n}\n\nfunction noResults(query: string): void {\n log.warn(`Nothing matches \"${query}\".`)\n console.log(pc.dim(\" Try fewer or more general words, or run `vantage docs --list` to browse every page.\"))\n}\n\nfunction meta(entry: DocEntry) {\n return {\n slug: entry.slug,\n title: entry.title,\n description: entry.description,\n section: entry.section,\n sectionTitle: entry.sectionTitle,\n command: `vantage docs ${entry.slug}`,\n }\n}\n\n/** Default mode: rank the corpus with BM25 and show the best passage of each hit. */\nfunction runRanked(entries: DocEntry[], query: string, lang: DocLang, limit: number, json: boolean): number {\n const hits = buildIndex(entries).search(query)\n const shown = hits.slice(0, limit)\n const passage = (hit: SearchHit) => snippet(hit.body, hit.terms)\n\n if (json) {\n printJson({\n query,\n mode: \"bm25\",\n lang,\n count: hits.length,\n results: shown.map((hit) => ({\n ...meta(hit.entry),\n score: Math.round(hit.score * 1000) / 1000,\n snippet: passage(hit),\n })),\n })\n return 0\n }\n\n if (hits.length === 0) {\n noResults(query)\n return 0\n }\n\n const words = queryPhrases(query)\n const width = Math.max(...shown.map((hit) => hit.entry.slug.length))\n header(hits.length, query, lang, \"bm25\")\n for (const hit of shown) {\n const title = `${hit.entry.title}${pc.dim(` · ${hit.entry.sectionTitle}`)}`\n console.log(` ${pc.cyan(hit.entry.slug.padEnd(width))} ${title}`)\n const text = passage(hit)\n if (text) console.log(` ${\" \".repeat(width)} ${paintTerms(text, words)}`)\n }\n footer(hits.length, shown.length, [\n \"vantage docs <name> open one result --regex treat the query as a regular expression\",\n \"vantage search --json machine-readable --limit max results (default 10)\",\n ])\n return 0\n}\n\n/** `--regex` mode: scan names, titles and bodies for a regular expression. */\nfunction runRegex(entries: DocEntry[], query: string, lang: DocLang, limit: number, json: boolean): number {\n let scan: RegExp\n let probe: RegExp\n try {\n scan = new RegExp(query, \"gi\")\n probe = new RegExp(query, \"i\")\n } catch (err) {\n log.error(err instanceof Error ? err.message : `Invalid regular expression: ${String(err)}`)\n return 1\n }\n\n const results: { entry: DocEntry; matchCount: number; matches: { line: number; text: string }[] }[] = []\n for (const entry of entries) {\n const lines = readDoc(entry).split(\"\\n\")\n const matches: { line: number; text: string }[] = []\n let matchCount = 0\n for (let i = 0; i < lines.length; i++) {\n const found = [...lines[i]!.matchAll(scan)]\n if (found.length === 0) continue\n matchCount += found.length\n if (matches.length < MAX_REGEX_LINES) {\n matches.push({ line: i + 1, text: lines[i]!.replace(/\\s+/g, \" \").trim() })\n }\n }\n const inMeta = probe.test(entry.slug) || probe.test(entry.title) || probe.test(entry.description)\n if (matchCount === 0 && !inMeta) continue\n results.push({ entry, matchCount, matches })\n }\n // Stable sort: pages with more matches first, catalog order within ties.\n results.sort((a, b) => b.matchCount - a.matchCount)\n const shown = results.slice(0, limit)\n\n if (json) {\n printJson({\n query,\n mode: \"regex\",\n lang,\n count: results.length,\n results: shown.map((result) => ({\n ...meta(result.entry),\n matchCount: result.matchCount,\n matches: result.matches,\n })),\n })\n return 0\n }\n\n if (results.length === 0) {\n noResults(query)\n return 0\n }\n\n header(results.length, query, lang, \"regex\")\n for (const result of shown) {\n // A page can match on its name, title or description alone — with no body line to show.\n const count = pc.dim(\n result.matchCount ? ` ${result.matchCount} match${result.matchCount === 1 ? \"\" : \"es\"}` : \" name match\",\n )\n console.log(` ${pc.cyan(result.entry.slug)} ${result.entry.title}${count}`)\n for (const match of result.matches) {\n console.log(` ${pc.dim(String(match.line).padStart(4))} ${paintMatches(match.text, scan)}`)\n }\n }\n footer(results.length, shown.length, [\n \"vantage docs <name> open one result --limit max results (default 10)\",\n \"vantage search --json machine-readable --lang ja | en\",\n ])\n return 0\n}\n\n/** `vantage search <query> [--regex] [--limit n] [--json] [--lang ja|en]` */\nexport async function search(_root: string, args: ParsedArgs): Promise<number> {\n const query = args.positionals.slice(1).join(\" \").trim()\n if (!query) {\n log.error(\"Usage: vantage search <query> [--regex] [--limit <n>] [--lang ja|en] [--json]\")\n return 1\n }\n\n const catalog = loadCatalog()\n if (!catalog) {\n log.error(\"The bundled documentation is missing. Reinstall @squadbase/vantage, or run `pnpm build` in the framework repo.\")\n return 1\n }\n\n const langFlag = args.flags.lang\n if (langFlag !== undefined && !isDocLang(langFlag)) {\n log.error(`Unknown --lang \"${String(langFlag)}\". Available: ${DOC_LANGS.join(\", \")}`)\n return 1\n }\n const lang: DocLang = isDocLang(langFlag) ? langFlag : DEFAULT_DOC_LANG\n\n const entries = docsForLang(catalog, lang)\n if (entries.length === 0) {\n log.error(`No documentation bundled for \"${lang}\".`)\n return 1\n }\n\n // Pages that opted out with `search: false` (e.g. the changelog) are still\n // reachable via `vantage docs` but never surface here.\n const searchable = entries.filter((entry) => entry.searchable !== false)\n\n const limit = parseLimit(args.flags.limit, DEFAULT_LIMIT)\n const json = Boolean(args.flags.json)\n return args.flags.regex\n ? runRegex(searchable, query, lang, limit, json)\n : runRanked(searchable, query, lang, limit, json)\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/search-index.ts","../src/cli/search.ts"],"names":[],"mappings":";;;;;;;;AAiBA,IAAM,aAAA,GAAgB,EAAE,IAAA,EAAM,CAAA,EAAG,OAAO,CAAA,EAAG,WAAA,EAAa,CAAA,EAAG,IAAA,EAAM,CAAA,EAAE;AAGnE,IAAM,EAAA,GAAK,GAAA;AACX,IAAM,CAAA,GAAI,IAAA;AAOV,IAAM,QAAA,GAAW,yBAAA;AACjB,IAAM,QAAA,GAAW,aAAA;AAEjB,IAAM,gBAAA,GAAmB,4BAAA;AACzB,IAAM,MAAA,GAAS,aAAA;AASf,IAAM,SAAA,GAAY,0BAAA;AAClB,IAAM,WAAA,GAAc,SAAA;AAGpB,SAAS,SAAS,IAAA,EAAsB;AACtC,EAAA,IAAI,IAAA,CAAK,MAAA,IAAU,CAAA,IAAK,IAAA,CAAK,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA,CAAA,CAAA;AACzE,EAAA,IAAI,KAAK,MAAA,IAAU,CAAA,IAAK,IAAA,CAAK,QAAA,CAAS,GAAG,CAAA,IAAK,CAAC,aAAA,CAAc,IAAA,CAAK,IAAI,CAAA,EAAG,OAAO,IAAA,CAAK,KAAA,CAAM,GAAG,EAAE,CAAA;AAChG,EAAA,OAAO,IAAA;AACT;AASO,SAAS,SAAS,IAAA,EAAwB;AAC/C,EAAA,MAAM,UAAA,GAAa,KAChB,SAAA,CAAU,MAAM,EAChB,OAAA,CAAQ,oBAAA,EAAsB,OAAO,CAAA,CACrC,WAAA,EAAY;AACf,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,KAAA,MAAW,KAAA,IAAS,UAAA,CAAW,QAAA,CAAS,QAAQ,CAAA,EAAG;AACjD,IAAA,MAAM,GAAA,GAAM,MAAM,CAAC,CAAA;AACnB,IAAA,IAAI,QAAA,CAAS,IAAA,CAAK,GAAG,CAAA,EAAG;AACtB,MAAA,MAAA,CAAO,IAAA,CAAK,QAAA,CAAS,GAAG,CAAC,CAAA;AACzB,MAAA;AAAA,IACF;AACA,IAAA,KAAA,MAAW,WAAW,GAAA,CAAI,KAAA,CAAM,SAAS,CAAA,IAAK,EAAC,EAAG;AAGhD,MAAA,IAAI,QAAQ,MAAA,KAAW,CAAA,IAAK,WAAA,CAAY,IAAA,CAAK,OAAO,CAAA,EAAG;AAGvD,MAAA,IAAI,OAAA,CAAQ,UAAU,CAAA,EAAG;AACvB,QAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,QAAA;AAAA,MACF;AACA,MAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AACnB,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,OAAA,CAAQ,SAAS,CAAA,EAAG,CAAA,EAAA,EAAK,MAAA,CAAO,IAAA,CAAK,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,CAAA,GAAI,CAAC,CAAC,CAAA;AAAA,IAClF;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAQO,SAAS,aAAa,KAAA,EAAyB;AACpD,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,KAAA,MAAW,SAAS,KAAA,CAAM,SAAA,CAAU,MAAM,CAAA,CAAE,QAAA,CAAS,gBAAgB,CAAA,EAAG;AACtE,IAAA,MAAM,GAAA,GAAM,MAAM,CAAC,CAAA;AACnB,IAAA,IAAI,CAAC,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,EAAG;AACrB,MAAA,OAAA,CAAQ,KAAK,GAAG,CAAA;AAChB,MAAA;AAAA,IACF;AACA,IAAA,KAAA,MAAW,WAAW,GAAA,CAAI,KAAA,CAAM,SAAS,CAAA,IAAK,EAAC,EAAG;AAChD,MAAA,IAAI,QAAQ,MAAA,KAAW,CAAA,IAAK,WAAA,CAAY,IAAA,CAAK,OAAO,CAAA,EAAG;AACvD,MAAA,OAAA,CAAQ,KAAK,OAAO,CAAA;AAAA,IACtB;AAAA,EACF;AACA,EAAA,OAAO,CAAC,GAAG,IAAI,GAAA,CAAI,OAAO,CAAC,CAAA;AAC7B;AA0BO,SAAS,WAAW,OAAA,EAAkC;AAC3D,EAAA,MAAM,IAAA,GAAqB,OAAA,CAAQ,GAAA,CAAI,CAAC,KAAA,KAAU;AAChD,IAAA,MAAM,IAAA,GAAO,QAAQ,KAAK,CAAA;AAC1B,IAAA,MAAM,EAAA,uBAAS,GAAA,EAAoB;AACnC,IAAA,IAAI,MAAA,GAAS,CAAA;AACb,IAAA,MAAM,GAAA,GAAM,CAAC,IAAA,EAAc,MAAA,KAAmB;AAC5C,MAAA,KAAA,MAAW,KAAA,IAAS,QAAA,CAAS,IAAI,CAAA,EAAG;AAClC,QAAA,EAAA,CAAG,IAAI,KAAA,EAAA,CAAQ,EAAA,CAAG,IAAI,KAAK,CAAA,IAAK,KAAK,MAAM,CAAA;AAC3C,QAAA,MAAA,IAAU,MAAA;AAAA,MACZ;AAAA,IACF,CAAA;AACA,IAAA,GAAA,CAAI,KAAA,CAAM,IAAA,EAAM,aAAA,CAAc,IAAI,CAAA;AAClC,IAAA,GAAA,CAAI,KAAA,CAAM,KAAA,EAAO,aAAA,CAAc,KAAK,CAAA;AACpC,IAAA,GAAA,CAAI,KAAA,CAAM,WAAA,EAAa,aAAA,CAAc,WAAW,CAAA;AAChD,IAAA,GAAA,CAAI,IAAA,EAAM,cAAc,IAAI,CAAA;AAC5B,IAAA,OAAO,EAAE,KAAA,EAAO,IAAA,EAAM,EAAA,EAAI,MAAA,EAAO;AAAA,EACnC,CAAC,CAAA;AAED,EAAA,MAAM,EAAA,uBAAS,GAAA,EAAoB;AACnC,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,KAAA,MAAW,IAAA,IAAQ,GAAA,CAAI,EAAA,CAAG,IAAA,EAAK,EAAG,EAAA,CAAG,GAAA,CAAI,IAAA,EAAA,CAAO,EAAA,CAAG,GAAA,CAAI,IAAI,CAAA,IAAK,KAAK,CAAC,CAAA;AAAA,EACxE;AACA,EAAA,MAAM,QAAQ,IAAA,CAAK,MAAA;AACnB,EAAA,MAAM,SAAA,GAAY,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,CAAC,GAAA,EAAK,GAAA,KAAQ,GAAA,GAAM,GAAA,CAAI,MAAA,EAAQ,CAAC,CAAA,GAAI,KAAA,GAAQ,CAAA;AAEnF,EAAA,OAAO;AAAA,IACL,OAAO,KAAA,EAA4B;AACjC,MAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,IAAI,IAAI,QAAA,CAAS,KAAK,CAAC,CAAC,CAAA;AAC1C,MAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,EAAC;AAEhC,MAAA,MAAM,OAAoB,EAAC;AAC3B,MAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,QAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,QAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,UAAA,MAAM,EAAA,GAAK,GAAA,CAAI,EAAA,CAAG,GAAA,CAAI,IAAI,CAAA;AAC1B,UAAA,IAAI,CAAC,EAAA,EAAI;AACT,UAAA,MAAM,CAAA,GAAI,EAAA,CAAG,GAAA,CAAI,IAAI,CAAA,IAAK,CAAA;AAC1B,UAAA,MAAM,GAAA,GAAM,KAAK,GAAA,CAAI,CAAA,GAAA,CAAK,QAAQ,CAAA,GAAI,GAAA,KAAQ,IAAI,GAAA,CAAI,CAAA;AACtD,UAAA,MAAM,IAAA,GAAO,CAAA,GAAI,CAAA,GAAK,CAAA,GAAI,IAAI,MAAA,GAAU,SAAA;AACxC,UAAA,KAAA,IAAS,GAAA,IAAQ,EAAA,IAAM,EAAA,GAAK,CAAA,CAAA,IAAO,KAAK,EAAA,GAAK,IAAA,CAAA,CAAA;AAAA,QAC/C;AACA,QAAA,IAAI,KAAA,GAAQ,CAAA,EAAG,IAAA,CAAK,IAAA,CAAK,EAAE,KAAA,EAAO,GAAA,CAAI,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,IAAA,EAAM,GAAA,CAAI,MAAM,CAAA;AAAA,MAC7E;AACA,MAAA,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,EAAE,KAAA,GAAQ,CAAA,CAAE,KAAA,IAAS,CAAA,CAAE,MAAM,IAAA,CAAK,aAAA,CAAc,CAAA,CAAE,KAAA,CAAM,IAAI,CAAC,CAAA;AACjF,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,GACF;AACF;AAGA,IAAM,cAAA,GAAiB,GAAA;AAOhB,SAAS,OAAA,CAAQ,IAAA,EAAc,KAAA,EAAiB,MAAA,GAAS,cAAA,EAAwB;AACtF,EAAA,IAAI,IAAA,GAAO,EAAA;AACX,EAAA,IAAI,QAAA,GAAW,CAAA;AACf,EAAA,IAAI,SAAA,GAAY,CAAA;AAChB,EAAA,IAAI,aAAA,GAAgB,IAAA;AAGpB,EAAA,KAAA,MAAW,OAAO,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,EAAG;AAC3C,IAAA,MAAM,IAAA,GAAO,GAAA,CAAI,OAAA,CAAQ,aAAA,EAAe,EAAE,EAAE,OAAA,CAAQ,MAAA,EAAQ,GAAG,CAAA,CAAE,IAAA,EAAK;AACtE,IAAA,IAAI,CAAC,IAAA,IAAQ,uBAAA,CAAwB,IAAA,CAAK,IAAI,CAAA,EAAG;AACjD,IAAA,MAAM,QAAA,GAAW,KAAK,WAAA,EAAY;AAClC,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA;AACnC,IAAA,IAAI,IAAA,GAAO,CAAA;AACX,IAAA,IAAI,KAAA,GAAQ,EAAA;AACZ,IAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,MAAA,MAAM,EAAA,GAAK,QAAA,CAAS,OAAA,CAAQ,IAAI,CAAA;AAChC,MAAA,IAAI,OAAO,EAAA,EAAI;AACf,MAAA,IAAA,EAAA;AACA,MAAA,IAAI,KAAA,KAAU,EAAA,IAAM,EAAA,GAAK,KAAA,EAAO,KAAA,GAAQ,EAAA;AAAA,IAC1C;AAEA,IAAA,IAAI,IAAA,GAAO,YAAa,IAAA,KAAS,QAAA,IAAY,OAAO,CAAA,IAAK,aAAA,IAAiB,CAAC,OAAA,EAAU;AACnF,MAAA,IAAA,GAAO,IAAA;AACP,MAAA,QAAA,GAAW,IAAA;AACX,MAAA,SAAA,GAAY,KAAA;AACZ,MAAA,aAAA,GAAgB,OAAA;AAAA,IAClB;AAAA,EACF;AAEA,EAAA,IAAI,CAAC,UAAU,OAAO,EAAA;AACtB,EAAA,IAAI,IAAA,CAAK,MAAA,IAAU,MAAA,EAAQ,OAAO,IAAA;AAElC,EAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,CAAI,CAAA,EAAG,YAAY,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,CAAC,CAAC,CAAA;AAC5D,EAAA,MAAM,OAAO,IAAA,CAAK,KAAA,CAAM,OAAO,KAAA,GAAQ,MAAM,EAAE,IAAA,EAAK;AACpD,EAAA,OAAO,CAAA,EAAG,KAAA,GAAQ,CAAA,GAAI,QAAA,GAAM,EAAE,CAAA,EAAG,IAAI,CAAA,EAAG,KAAA,GAAQ,MAAA,GAAS,IAAA,CAAK,MAAA,GAAS,WAAM,EAAE,CAAA,CAAA;AACjF;;;AClNA,IAAM,aAAA,GAAgB,EAAA;AAGtB,IAAM,eAAA,GAAkB,CAAA;AAGxB,SAAS,UAAA,CAAW,OAAqC,QAAA,EAA0B;AACjF,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,MAAM,CAAA,GAAI,OAAO,KAAK,CAAA;AACtB,IAAA,IAAI,OAAO,SAAA,CAAU,CAAC,CAAA,IAAK,CAAA,GAAI,GAAG,OAAO,CAAA;AAAA,EAC3C;AACA,EAAA,OAAO,QAAA;AACT;AAEA,SAAS,aAAa,KAAA,EAAuB;AAC3C,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,qBAAA,EAAuB,MAAM,CAAA;AACpD;AAGA,SAAS,YAAA,CAAa,MAAc,EAAA,EAAoB;AACtD,EAAA,IAAI,CAAC,OAAA,CAAQ,MAAA,CAAO,KAAA,EAAO,OAAO,IAAA;AAClC,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,KAAA,MAAW,KAAA,IAAS,IAAA,CAAK,QAAA,CAAS,EAAE,CAAA,EAAG;AACrC,IAAA,MAAM,EAAA,GAAK,MAAM,KAAA,IAAS,CAAA;AAC1B,IAAA,IAAI,CAAC,KAAA,CAAM,CAAC,CAAA,EAAG;AACf,IAAA,GAAA,IAAO,EAAA,CAAG,GAAA,CAAI,IAAA,CAAK,KAAA,CAAM,IAAA,EAAM,EAAE,CAAC,CAAA,GAAI,EAAA,CAAG,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA;AACxD,IAAA,IAAA,GAAO,EAAA,GAAK,KAAA,CAAM,CAAC,CAAA,CAAE,MAAA;AAAA,EACvB;AACA,EAAA,OAAO,MAAM,EAAA,CAAG,GAAA,CAAI,IAAA,CAAK,KAAA,CAAM,IAAI,CAAC,CAAA;AACtC;AAGA,SAAS,UAAA,CAAW,MAAc,KAAA,EAAyB;AACzD,EAAA,IAAI,CAAC,OAAA,CAAQ,MAAA,CAAO,KAAA,EAAO,OAAO,IAAA;AAClC,EAAA,IAAI,MAAM,MAAA,KAAW,CAAA,EAAG,OAAO,EAAA,CAAG,IAAI,IAAI,CAAA;AAC1C,EAAA,OAAO,YAAA,CAAa,IAAA,EAAM,IAAI,MAAA,CAAO,KAAA,CAAM,GAAA,CAAI,YAAY,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA,EAAG,IAAI,CAAC,CAAA;AAC/E;AAEA,SAAS,MAAA,CAAO,KAAA,EAAe,KAAA,EAAe,IAAA,EAAe,IAAA,EAAoB;AAC/E,EAAA,MAAM,KAAA,GAAQ,GAAG,KAAK,CAAA,OAAA,EAAU,UAAU,CAAA,GAAI,EAAA,GAAK,GAAG,CAAA,MAAA,EAAS,KAAK,CAAA,CAAA,CAAA;AACpE,EAAA,OAAA,CAAQ,IAAI,EAAE,CAAA;AACd,EAAA,OAAA,CAAQ,GAAA,CAAI,EAAA,CAAG,IAAA,CAAK,KAAK,CAAA,GAAI,EAAA,CAAG,GAAA,CAAI,CAAA,EAAA,EAAK,IAAI,CAAA,MAAA,EAAM,IAAI,CAAA,CAAE,CAAC,CAAA;AAC1D,EAAA,OAAA,CAAQ,IAAI,EAAE,CAAA;AAChB;AAEA,SAAS,MAAA,CAAO,KAAA,EAAe,KAAA,EAAe,KAAA,EAAuB;AACnE,EAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,IAAA,OAAA,CAAQ,IAAI,EAAE,CAAA;AACd,IAAA,OAAA,CAAQ,IAAI,EAAA,CAAG,GAAA,CAAI,KAAK,KAAA,GAAQ,KAAK,wCAAmC,CAAC,CAAA;AAAA,EAC3E;AACA,EAAA,OAAA,CAAQ,IAAI,EAAE,CAAA;AACd,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO,OAAA,CAAQ,IAAI,EAAA,CAAG,GAAA,CAAI,IAAI,CAAC,CAAA;AACpD;AAEA,SAAS,UAAU,KAAA,EAAqB;AACtC,EAAA,GAAA,CAAI,IAAA,CAAK,CAAA,iBAAA,EAAoB,KAAK,CAAA,EAAA,CAAI,CAAA;AACtC,EAAA,OAAA,CAAQ,GAAA,CAAI,EAAA,CAAG,GAAA,CAAI,uFAAuF,CAAC,CAAA;AAC7G;AAEA,SAAS,KAAK,KAAA,EAAiB;AAC7B,EAAA,OAAO;AAAA,IACL,MAAM,KAAA,CAAM,IAAA;AAAA,IACZ,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,aAAa,KAAA,CAAM,WAAA;AAAA,IACnB,SAAS,KAAA,CAAM,OAAA;AAAA,IACf,cAAc,KAAA,CAAM,YAAA;AAAA,IACpB,OAAA,EAAS,CAAA,aAAA,EAAgB,KAAA,CAAM,IAAI,CAAA;AAAA,GACrC;AACF;AAGA,SAAS,SAAA,CAAU,OAAA,EAAqB,KAAA,EAAe,IAAA,EAAe,OAAe,IAAA,EAAuB;AAC1G,EAAA,MAAM,IAAA,GAAO,UAAA,CAAW,OAAO,CAAA,CAAE,OAAO,KAAK,CAAA;AAC7C,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA;AACjC,EAAA,MAAM,UAAU,CAAC,GAAA,KAAmB,QAAQ,GAAA,CAAI,IAAA,EAAM,IAAI,KAAK,CAAA;AAE/D,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,SAAA,CAAU;AAAA,MACR,KAAA;AAAA,MACA,IAAA,EAAM,MAAA;AAAA,MACN,IAAA;AAAA,MACA,OAAO,IAAA,CAAK,MAAA;AAAA,MACZ,OAAA,EAAS,KAAA,CAAM,GAAA,CAAI,CAAC,GAAA,MAAS;AAAA,QAC3B,GAAG,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAAA,QACjB,OAAO,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,KAAA,GAAQ,GAAI,CAAA,GAAI,GAAA;AAAA,QACtC,OAAA,EAAS,QAAQ,GAAG;AAAA,OACtB,CAAE;AAAA,KACH,CAAA;AACD,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AACrB,IAAA,SAAA,CAAU,KAAK,CAAA;AACf,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,MAAM,KAAA,GAAQ,aAAa,KAAK,CAAA;AAChC,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,GAAG,KAAA,CAAM,GAAA,CAAI,CAAC,GAAA,KAAQ,GAAA,CAAI,KAAA,CAAM,IAAA,CAAK,MAAM,CAAC,CAAA;AACnE,EAAA,MAAA,CAAO,IAAA,CAAK,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,MAAM,CAAA;AACvC,EAAA,KAAA,MAAW,OAAO,KAAA,EAAO;AACvB,IAAA,MAAM,KAAA,GAAQ,CAAA,EAAG,GAAA,CAAI,KAAA,CAAM,KAAK,CAAA,EAAG,EAAA,CAAG,GAAA,CAAI,CAAA,MAAA,EAAM,GAAA,CAAI,KAAA,CAAM,YAAY,EAAE,CAAC,CAAA,CAAA;AACzE,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,EAAA,EAAK,EAAA,CAAG,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,IAAA,CAAK,MAAA,CAAO,KAAK,CAAC,CAAC,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AAClE,IAAA,MAAM,IAAA,GAAO,QAAQ,GAAG,CAAA;AACxB,IAAA,IAAI,IAAA,EAAM,OAAA,CAAQ,GAAA,CAAI,CAAA,EAAA,EAAK,GAAA,CAAI,MAAA,CAAO,KAAK,CAAC,CAAA,EAAA,EAAK,UAAA,CAAW,IAAA,EAAM,KAAK,CAAC,CAAA,CAAE,CAAA;AAAA,EAC5E;AACA,EAAA,MAAA,CAAO,IAAA,CAAK,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAQ;AAAA,IAChC,kGAAA;AAAA,IACA;AAAA,GACD,CAAA;AACD,EAAA,OAAO,CAAA;AACT;AAGA,SAAS,QAAA,CAAS,OAAA,EAAqB,KAAA,EAAe,IAAA,EAAe,OAAe,IAAA,EAAuB;AACzG,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI;AACF,IAAA,IAAA,GAAO,IAAI,MAAA,CAAO,KAAA,EAAO,IAAI,CAAA;AAC7B,IAAA,KAAA,GAAQ,IAAI,MAAA,CAAO,KAAA,EAAO,GAAG,CAAA;AAAA,EAC/B,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,CAAI,KAAA,CAAM,eAAe,KAAA,GAAQ,GAAA,CAAI,UAAU,CAAA,4BAAA,EAA+B,MAAA,CAAO,GAAG,CAAC,CAAA,CAAE,CAAA;AAC3F,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,MAAM,UAAgG,EAAC;AACvG,EAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAK,CAAA,CAAE,MAAM,IAAI,CAAA;AACvC,IAAA,MAAM,UAA4C,EAAC;AACnD,IAAA,IAAI,UAAA,GAAa,CAAA;AACjB,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,MAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,KAAA,CAAM,CAAC,CAAA,CAAG,QAAA,CAAS,IAAI,CAAC,CAAA;AAC1C,MAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACxB,MAAA,UAAA,IAAc,KAAA,CAAM,MAAA;AACpB,MAAA,IAAI,OAAA,CAAQ,SAAS,eAAA,EAAiB;AACpC,QAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,IAAA,EAAM,CAAA,GAAI,GAAG,IAAA,EAAM,KAAA,CAAM,CAAC,CAAA,CAAG,QAAQ,MAAA,EAAQ,GAAG,CAAA,CAAE,IAAA,IAAQ,CAAA;AAAA,MAC3E;AAAA,IACF;AACA,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,IAAK,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA,IAAK,KAAA,CAAM,IAAA,CAAK,MAAM,WAAW,CAAA;AAChG,IAAA,IAAI,UAAA,KAAe,CAAA,IAAK,CAAC,MAAA,EAAQ;AACjC,IAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,KAAA,EAAO,UAAA,EAAY,SAAS,CAAA;AAAA,EAC7C;AAEA,EAAA,OAAA,CAAQ,KAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,UAAA,GAAa,EAAE,UAAU,CAAA;AAClD,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA;AAEpC,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,SAAA,CAAU;AAAA,MACR,KAAA;AAAA,MACA,IAAA,EAAM,OAAA;AAAA,MACN,IAAA;AAAA,MACA,OAAO,OAAA,CAAQ,MAAA;AAAA,MACf,OAAA,EAAS,KAAA,CAAM,GAAA,CAAI,CAAC,MAAA,MAAY;AAAA,QAC9B,GAAG,IAAA,CAAK,MAAA,CAAO,KAAK,CAAA;AAAA,QACpB,YAAY,MAAA,CAAO,UAAA;AAAA,QACnB,SAAS,MAAA,CAAO;AAAA,OAClB,CAAE;AAAA,KACH,CAAA;AACD,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,IAAA,SAAA,CAAU,KAAK,CAAA;AACf,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,OAAO,CAAA;AAC3C,EAAA,KAAA,MAAW,UAAU,KAAA,EAAO;AAE1B,IAAA,MAAM,QAAQ,EAAA,CAAG,GAAA;AAAA,MACf,MAAA,CAAO,UAAA,GAAa,CAAA,EAAA,EAAK,MAAA,CAAO,UAAU,CAAA,MAAA,EAAS,MAAA,CAAO,UAAA,KAAe,CAAA,GAAI,EAAA,GAAK,IAAI,CAAA,CAAA,GAAK;AAAA,KAC7F;AACA,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,EAAA,EAAK,EAAA,CAAG,IAAA,CAAK,OAAO,KAAA,CAAM,IAAI,CAAC,CAAA,EAAA,EAAK,MAAA,CAAO,KAAA,CAAM,KAAK,CAAA,EAAG,KAAK,CAAA,CAAE,CAAA;AAC5E,IAAA,KAAA,MAAW,KAAA,IAAS,OAAO,OAAA,EAAS;AAClC,MAAA,OAAA,CAAQ,IAAI,CAAA,IAAA,EAAO,EAAA,CAAG,IAAI,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA,CAAE,QAAA,CAAS,CAAC,CAAC,CAAC,CAAA,EAAA,EAAK,YAAA,CAAa,MAAM,IAAA,EAAM,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,IAChG;AAAA,EACF;AACA,EAAA,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAQ;AAAA,IACnC,mFAAA;AAAA,IACA;AAAA,GACD,CAAA;AACD,EAAA,OAAO,CAAA;AACT;AAGA,eAAsB,MAAA,CAAO,OAAe,IAAA,EAAmC;AAC7E,EAAA,MAAM,KAAA,GAAQ,KAAK,WAAA,CAAY,KAAA,CAAM,CAAC,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA,CAAE,IAAA,EAAK;AACvD,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,GAAA,CAAI,MAAM,+EAA+E,CAAA;AACzF,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,MAAM,UAAU,WAAA,EAAY;AAC5B,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,GAAA,CAAI,MAAM,gHAAgH,CAAA;AAC1H,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,MAAM,QAAA,GAAW,KAAK,KAAA,CAAM,IAAA;AAC5B,EAAA,IAAI,QAAA,KAAa,MAAA,IAAa,CAAC,SAAA,CAAU,QAAQ,CAAA,EAAG;AAClD,IAAA,GAAA,CAAI,KAAA,CAAM,CAAA,gBAAA,EAAmB,MAAA,CAAO,QAAQ,CAAC,iBAAiB,SAAA,CAAU,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AACpF,IAAA,OAAO,CAAA;AAAA,EACT;AACA,EAAA,MAAM,IAAA,GAAgB,SAAA,CAAU,QAAQ,CAAA,GAAI,QAAA,GAAW,gBAAA;AAEvD,EAAA,MAAM,OAAA,GAAU,WAAA,CAAY,OAAA,EAAS,IAAI,CAAA;AACzC,EAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,IAAA,GAAA,CAAI,KAAA,CAAM,CAAA,8BAAA,EAAiC,IAAI,CAAA,EAAA,CAAI,CAAA;AACnD,IAAA,OAAO,CAAA;AAAA,EACT;AAIA,EAAA,MAAM,aAAa,OAAA,CAAQ,MAAA,CAAO,CAAC,KAAA,KAAU,KAAA,CAAM,eAAe,KAAK,CAAA;AAEvE,EAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,IAAA,CAAK,KAAA,CAAM,OAAO,aAAa,CAAA;AACxD,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AACpC,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,KAAA,GACd,QAAA,CAAS,YAAY,KAAA,EAAO,IAAA,EAAM,KAAA,EAAO,IAAI,IAC7C,SAAA,CAAU,UAAA,EAAY,KAAA,EAAO,IAAA,EAAM,OAAO,IAAI,CAAA;AACpD","file":"search-5LC4XPB5.js","sourcesContent":["import { readDoc, type DocEntry } from \"./docs-catalog\"\n\n/**\n * A tiny BM25F ranker over the bundled documentation. The corpus is the catalog\n * `docs-catalog.ts` exposes — the same one `vantage docs` prints, so search never\n * creates a second source of truth.\n *\n * The index is built at run time: 65 pages per language (~300 KB) tokenize in a\n * few milliseconds, which is cheaper than shipping and version-locking a\n * prebuilt index alongside the docs bundle.\n */\n\n/**\n * Field weights. A name or a title match says far more about relevance than one\n * more occurrence in a long body, and BM25F models that as a weighted term\n * frequency (and a matching weighted document length).\n */\nconst FIELD_WEIGHTS = { slug: 3, title: 3, description: 2, body: 1 } as const\n\n/** Standard BM25 constants: term-frequency saturation and length normalization. */\nconst K1 = 1.2\nconst B = 0.75\n\n/**\n * Latin/digit runs, or runs of Japanese script (kana + CJK ideographs). CJK\n * punctuation (U+3000–U+303F, 。and 、) is deliberately outside the ranges, so\n * runs break at sentence boundaries.\n */\nconst TOKEN_RE = /[a-z0-9]+|[-ヿ㐀-䶿一-鿿]+/g\nconst LATIN_RE = /^[a-z0-9]+$/\n/** `TOKEN_RE`, but before lowercasing — for text that is not being indexed. */\nconst TOKEN_RE_ANYCASE = /[a-zA-Z0-9]+|[-ヿ㐀-䶿一-鿿]+/g\nconst CJK_RE = /[-ヿ㐀-䶿一-鿿]/\n\n/**\n * One run of a single script: hiragana (U+3041–U+309F), katakana (U+30A0–U+30FF,\n * so ー stays inside テーブル), or kanji. Japanese writes content words in\n * katakana and kanji and the grammatical glue between them in hiragana, so\n * cutting at every script change segments 「テーブルにページングを付けたい」into\n * テーブル · に · ページング · を · 付 · けたい without a morphological analyser.\n */\nconst SCRIPT_RE = /[ぁ-ゟ]+|[゠-ヿ]+|[㐀-䶿一-鿿]+/g\nconst HIRAGANA_RE = /^[ぁ-ゟ]$/\n\n/** Plural forms, so `colors` finds `color` and `queries` finds `query`. */\nfunction singular(word: string): string {\n if (word.length >= 5 && word.endsWith(\"ies\")) return `${word.slice(0, -3)}y`\n if (word.length >= 4 && word.endsWith(\"s\") && !/(ss|us|is)$/.test(word)) return word.slice(0, -1)\n return word\n}\n\n/**\n * Split text into index terms. Latin runs become words (`DataTable` splits into\n * `data` + `table`, so a two-word query finds it). Japanese runs are segmented\n * by script change; each segment is indexed whole *and* as character bigrams,\n * so an exact word scores high while a near miss (ページング / ページネーション)\n * still shares enough terms to be found.\n */\nexport function tokenize(text: string): string[] {\n const normalized = text\n .normalize(\"NFKC\")\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .toLowerCase()\n const tokens: string[] = []\n for (const match of normalized.matchAll(TOKEN_RE)) {\n const run = match[0]!\n if (LATIN_RE.test(run)) {\n tokens.push(singular(run))\n continue\n }\n for (const segment of run.match(SCRIPT_RE) ?? []) {\n // A lone hiragana is a particle (を, に, が …): it appears in every page\n // and would make every page a match.\n if (segment.length === 1 && HIRAGANA_RE.test(segment)) continue\n // A 2-character segment is its own only bigram — pushing both would\n // double-count it.\n if (segment.length <= 2) {\n tokens.push(segment)\n continue\n }\n tokens.push(segment)\n for (let i = 0; i < segment.length - 1; i++) tokens.push(segment.slice(i, i + 2))\n }\n }\n return tokens\n}\n\n/**\n * The words a snippet should highlight: whole words and whole Japanese\n * segments as the user typed them, without the derived bigrams (highlighting\n * those would paint most of a Japanese line yellow) and without the singular\n * rewrite (which no longer appears verbatim in the text).\n */\nexport function queryPhrases(query: string): string[] {\n const phrases: string[] = []\n for (const match of query.normalize(\"NFKC\").matchAll(TOKEN_RE_ANYCASE)) {\n const run = match[0]!\n if (!CJK_RE.test(run)) {\n phrases.push(run)\n continue\n }\n for (const segment of run.match(SCRIPT_RE) ?? []) {\n if (segment.length === 1 && HIRAGANA_RE.test(segment)) continue\n phrases.push(segment)\n }\n }\n return [...new Set(phrases)]\n}\n\n/** One ranked document, with the body kept for snippet extraction. */\nexport interface SearchHit {\n entry: DocEntry\n score: number\n /** Query terms that were looked up — the input for `snippet()`. */\n terms: string[]\n body: string\n}\n\ninterface IndexedDoc {\n entry: DocEntry\n body: string\n /** Weighted term frequency across all fields. */\n tf: Map<string, number>\n /** Weighted document length. */\n length: number\n}\n\nexport interface SearchIndex {\n /** Every document with a non-zero score, best first. */\n search(query: string): SearchHit[]\n}\n\n/** Build the index for one language's catalog entries. */\nexport function buildIndex(entries: DocEntry[]): SearchIndex {\n const docs: IndexedDoc[] = entries.map((entry) => {\n const body = readDoc(entry)\n const tf = new Map<string, number>()\n let length = 0\n const add = (text: string, weight: number) => {\n for (const token of tokenize(text)) {\n tf.set(token, (tf.get(token) ?? 0) + weight)\n length += weight\n }\n }\n add(entry.slug, FIELD_WEIGHTS.slug)\n add(entry.title, FIELD_WEIGHTS.title)\n add(entry.description, FIELD_WEIGHTS.description)\n add(body, FIELD_WEIGHTS.body)\n return { entry, body, tf, length }\n })\n\n const df = new Map<string, number>()\n for (const doc of docs) {\n for (const term of doc.tf.keys()) df.set(term, (df.get(term) ?? 0) + 1)\n }\n const total = docs.length\n const avgLength = total ? docs.reduce((sum, doc) => sum + doc.length, 0) / total : 1\n\n return {\n search(query: string): SearchHit[] {\n const terms = [...new Set(tokenize(query))]\n if (terms.length === 0) return []\n\n const hits: SearchHit[] = []\n for (const doc of docs) {\n let score = 0\n for (const term of terms) {\n const tf = doc.tf.get(term)\n if (!tf) continue\n const n = df.get(term) ?? 0\n const idf = Math.log(1 + (total - n + 0.5) / (n + 0.5))\n const norm = 1 - B + (B * doc.length) / avgLength\n score += idf * ((tf * (K1 + 1)) / (tf + K1 * norm))\n }\n if (score > 0) hits.push({ entry: doc.entry, score, terms, body: doc.body })\n }\n hits.sort((a, b) => b.score - a.score || a.entry.slug.localeCompare(b.entry.slug))\n return hits\n },\n }\n}\n\n/** How much of a line to show around the first matched term. */\nconst SNIPPET_LENGTH = 150\n\n/**\n * Pick the passage that best covers the query terms. Lines are compared\n * lowercased only (no NFKC, no camelCase splitting) so offsets stay aligned\n * with the text that is printed.\n */\nexport function snippet(body: string, terms: string[], length = SNIPPET_LENGTH): string {\n let best = \"\"\n let bestHits = 0\n let bestIndex = 0\n let bestIsHeading = true\n\n // The first line is the page's own `# Title`, which the caller already shows.\n for (const raw of body.split(\"\\n\").slice(1)) {\n const line = raw.replace(/^\\s*[-*]\\s+/, \"\").replace(/\\s+/g, \" \").trim()\n if (!line || /^(```|~~~|\\|\\s*-{2,})/.test(line)) continue\n const haystack = line.toLowerCase()\n const heading = line.startsWith(\"#\")\n let hits = 0\n let first = -1\n for (const term of terms) {\n const at = haystack.indexOf(term)\n if (at === -1) continue\n hits++\n if (first === -1 || at < first) first = at\n }\n // Equal coverage: prose says more than a heading does.\n if (hits > bestHits || (hits === bestHits && hits > 0 && bestIsHeading && !heading)) {\n best = line\n bestHits = hits\n bestIndex = first\n bestIsHeading = heading\n }\n }\n\n if (!bestHits) return \"\"\n if (best.length <= length) return best\n\n const start = Math.max(0, bestIndex - Math.floor(length / 4))\n const text = best.slice(start, start + length).trim()\n return `${start > 0 ? \"…\" : \"\"}${text}${start + length < best.length ? \"…\" : \"\"}`\n}\n","import pc from \"picocolors\"\nimport {\n DEFAULT_DOC_LANG,\n DOC_LANGS,\n docsForLang,\n isDocLang,\n loadCatalog,\n readDoc,\n type DocEntry,\n type DocLang,\n} from \"./docs-catalog\"\nimport { buildIndex, queryPhrases, snippet, type SearchHit } from \"./search-index\"\nimport { log, printJson, type ParsedArgs } from \"./util\"\n\n/** Results shown when `--limit` is absent. */\nconst DEFAULT_LIMIT = 10\n\n/** Matching lines printed per page in regex mode (the count is always exact). */\nconst MAX_REGEX_LINES = 3\n\n/** Parse `--limit`, falling back silently — an off result list is not a failure. */\nfunction parseLimit(value: string | boolean | undefined, fallback: number): number {\n if (typeof value === \"string\") {\n const n = Number(value)\n if (Number.isInteger(n) && n > 0) return n\n }\n return fallback\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n}\n\n/** Dim a line, with every match of `re` picked out. Piped output stays plain. */\nfunction paintMatches(text: string, re: RegExp): string {\n if (!process.stdout.isTTY) return text\n let out = \"\"\n let last = 0\n for (const match of text.matchAll(re)) {\n const at = match.index ?? 0\n if (!match[0]) continue // zero-length match: nothing to highlight\n out += pc.dim(text.slice(last, at)) + pc.yellow(match[0])\n last = at + match[0].length\n }\n return out + pc.dim(text.slice(last))\n}\n\n/** Same, for the words of a natural-language query. */\nfunction paintTerms(text: string, words: string[]): string {\n if (!process.stdout.isTTY) return text\n if (words.length === 0) return pc.dim(text)\n return paintMatches(text, new RegExp(words.map(escapeRegExp).join(\"|\"), \"gi\"))\n}\n\nfunction header(count: number, query: string, lang: DocLang, mode: string): void {\n const label = `${count} result${count === 1 ? \"\" : \"s\"} for \"${query}\"`\n console.log(\"\")\n console.log(pc.bold(label) + pc.dim(` ${lang} · ${mode}`))\n console.log(\"\")\n}\n\nfunction footer(total: number, shown: number, lines: string[]): void {\n if (total > shown) {\n console.log(\"\")\n console.log(pc.dim(` ${total - shown} more — raise --limit to see them`))\n }\n console.log(\"\")\n for (const line of lines) console.log(pc.dim(line))\n}\n\nfunction noResults(query: string): void {\n log.warn(`Nothing matches \"${query}\".`)\n console.log(pc.dim(\" Try fewer or more general words, or run `vantage docs --list` to browse every page.\"))\n}\n\nfunction meta(entry: DocEntry) {\n return {\n slug: entry.slug,\n title: entry.title,\n description: entry.description,\n section: entry.section,\n sectionTitle: entry.sectionTitle,\n command: `vantage docs ${entry.slug}`,\n }\n}\n\n/** Default mode: rank the corpus with BM25 and show the best passage of each hit. */\nfunction runRanked(entries: DocEntry[], query: string, lang: DocLang, limit: number, json: boolean): number {\n const hits = buildIndex(entries).search(query)\n const shown = hits.slice(0, limit)\n const passage = (hit: SearchHit) => snippet(hit.body, hit.terms)\n\n if (json) {\n printJson({\n query,\n mode: \"bm25\",\n lang,\n count: hits.length,\n results: shown.map((hit) => ({\n ...meta(hit.entry),\n score: Math.round(hit.score * 1000) / 1000,\n snippet: passage(hit),\n })),\n })\n return 0\n }\n\n if (hits.length === 0) {\n noResults(query)\n return 0\n }\n\n const words = queryPhrases(query)\n const width = Math.max(...shown.map((hit) => hit.entry.slug.length))\n header(hits.length, query, lang, \"bm25\")\n for (const hit of shown) {\n const title = `${hit.entry.title}${pc.dim(` · ${hit.entry.sectionTitle}`)}`\n console.log(` ${pc.cyan(hit.entry.slug.padEnd(width))} ${title}`)\n const text = passage(hit)\n if (text) console.log(` ${\" \".repeat(width)} ${paintTerms(text, words)}`)\n }\n footer(hits.length, shown.length, [\n \"vantage docs <name> open one result --regex treat the query as a regular expression\",\n \"vantage search --json machine-readable --limit max results (default 10)\",\n ])\n return 0\n}\n\n/** `--regex` mode: scan names, titles and bodies for a regular expression. */\nfunction runRegex(entries: DocEntry[], query: string, lang: DocLang, limit: number, json: boolean): number {\n let scan: RegExp\n let probe: RegExp\n try {\n scan = new RegExp(query, \"gi\")\n probe = new RegExp(query, \"i\")\n } catch (err) {\n log.error(err instanceof Error ? err.message : `Invalid regular expression: ${String(err)}`)\n return 1\n }\n\n const results: { entry: DocEntry; matchCount: number; matches: { line: number; text: string }[] }[] = []\n for (const entry of entries) {\n const lines = readDoc(entry).split(\"\\n\")\n const matches: { line: number; text: string }[] = []\n let matchCount = 0\n for (let i = 0; i < lines.length; i++) {\n const found = [...lines[i]!.matchAll(scan)]\n if (found.length === 0) continue\n matchCount += found.length\n if (matches.length < MAX_REGEX_LINES) {\n matches.push({ line: i + 1, text: lines[i]!.replace(/\\s+/g, \" \").trim() })\n }\n }\n const inMeta = probe.test(entry.slug) || probe.test(entry.title) || probe.test(entry.description)\n if (matchCount === 0 && !inMeta) continue\n results.push({ entry, matchCount, matches })\n }\n // Stable sort: pages with more matches first, catalog order within ties.\n results.sort((a, b) => b.matchCount - a.matchCount)\n const shown = results.slice(0, limit)\n\n if (json) {\n printJson({\n query,\n mode: \"regex\",\n lang,\n count: results.length,\n results: shown.map((result) => ({\n ...meta(result.entry),\n matchCount: result.matchCount,\n matches: result.matches,\n })),\n })\n return 0\n }\n\n if (results.length === 0) {\n noResults(query)\n return 0\n }\n\n header(results.length, query, lang, \"regex\")\n for (const result of shown) {\n // A page can match on its name, title or description alone — with no body line to show.\n const count = pc.dim(\n result.matchCount ? ` ${result.matchCount} match${result.matchCount === 1 ? \"\" : \"es\"}` : \" name match\",\n )\n console.log(` ${pc.cyan(result.entry.slug)} ${result.entry.title}${count}`)\n for (const match of result.matches) {\n console.log(` ${pc.dim(String(match.line).padStart(4))} ${paintMatches(match.text, scan)}`)\n }\n }\n footer(results.length, shown.length, [\n \"vantage docs <name> open one result --limit max results (default 10)\",\n \"vantage search --json machine-readable --lang ja | en\",\n ])\n return 0\n}\n\n/** `vantage search <query> [--regex] [--limit n] [--json] [--lang ja|en]` */\nexport async function search(_root: string, args: ParsedArgs): Promise<number> {\n const query = args.positionals.slice(1).join(\" \").trim()\n if (!query) {\n log.error(\"Usage: vantage search <query> [--regex] [--limit <n>] [--lang ja|en] [--json]\")\n return 1\n }\n\n const catalog = loadCatalog()\n if (!catalog) {\n log.error(\"The bundled documentation is missing. Reinstall @squadbase/vantage, or run `pnpm build` in the framework repo.\")\n return 1\n }\n\n const langFlag = args.flags.lang\n if (langFlag !== undefined && !isDocLang(langFlag)) {\n log.error(`Unknown --lang \"${String(langFlag)}\". Available: ${DOC_LANGS.join(\", \")}`)\n return 1\n }\n const lang: DocLang = isDocLang(langFlag) ? langFlag : DEFAULT_DOC_LANG\n\n const entries = docsForLang(catalog, lang)\n if (entries.length === 0) {\n log.error(`No documentation bundled for \"${lang}\".`)\n return 1\n }\n\n // Pages that opted out with `search: false` (e.g. the changelog) are still\n // reachable via `vantage docs` but never surface here.\n const searchable = entries.filter((entry) => entry.searchable !== false)\n\n const limit = parseLimit(args.flags.limit, DEFAULT_LIMIT)\n const json = Boolean(args.flags.json)\n return args.flags.regex\n ? runRegex(searchable, query, lang, limit, json)\n : runRanked(searchable, query, lang, limit, json)\n}\n"]}
|
package/dist/table/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { FILE_PAGE_MAX_ROWS, FILE_PAGE_MAX_BYTES } from '../chunk-C2CX6GLX.js';
|
|
2
|
-
import { useQuery } from '../chunk-
|
|
3
|
-
import '../chunk-
|
|
2
|
+
import { useQuery } from '../chunk-V3LF7BE7.js';
|
|
3
|
+
import '../chunk-XQUSGIDG.js';
|
|
4
4
|
import { Loading, ErrorState } from '../chunk-5ZOP4SQR.js';
|
|
5
|
-
import { PageShell, PageShellHeader, PageShellHeading, PageShellTitle, PageShellMeta, PageShellActions, PageShellContent } from '../chunk-
|
|
6
|
-
import '../chunk-
|
|
5
|
+
import { PageShell, PageShellHeader, PageShellHeading, PageShellTitle, PageShellMeta, PageShellActions, PageShellContent } from '../chunk-AG6RZ2RR.js';
|
|
6
|
+
import '../chunk-OB6UBJXF.js';
|
|
7
7
|
import { Button } from '../chunk-PXRX5PEC.js';
|
|
8
8
|
import { cn } from '../chunk-A2UUGASH.js';
|
|
9
9
|
import { useRef, useState, useMemo, useLayoutEffect, useEffect, useCallback } from 'react';
|
|
@@ -70,12 +70,13 @@ function toSheet(name, rows) {
|
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
72
|
var numberFormat = new Intl.NumberFormat();
|
|
73
|
+
var WALL_CLOCK = { timeZone: "UTC" };
|
|
73
74
|
function formatCell(value, format) {
|
|
74
75
|
if (isEmpty(value)) return "";
|
|
75
76
|
if (format === "date" && typeof value === "string") return value;
|
|
76
|
-
if (format === "date" && value instanceof Date) return value.toLocaleDateString();
|
|
77
|
+
if (format === "date" && value instanceof Date) return value.toLocaleDateString(void 0, WALL_CLOCK);
|
|
77
78
|
if (format === "number" && typeof value === "number") return numberFormat.format(value);
|
|
78
|
-
if (value instanceof Date) return value.toLocaleString();
|
|
79
|
+
if (value instanceof Date) return value.toLocaleString(void 0, WALL_CLOCK);
|
|
79
80
|
if (typeof value === "boolean") return value ? "TRUE" : "FALSE";
|
|
80
81
|
return String(value);
|
|
81
82
|
}
|
package/dist/table/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/table/infer.ts","../../src/table/parse.ts","../../src/table/sheet-grid.tsx","../../src/table/table-viewer.tsx","../../src/table/file-page-view.tsx"],"names":["useState","useLayoutEffect","useRef","jsxs","jsx"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Turning raw rows into a readable table: which row is the header, what each\n * column holds, and how a cell should read. Deliberately shallow — the goal is\n * \"legible as a spreadsheet\", not a reimplementation of one. Formulas, charts\n * and cell formatting are dropped; their values are what survive.\n */\nimport { FILE_PAGE_MAX_ROWS } from \"../core/constants\"\nimport type { CellFormat, TableColumn, TableSheet } from \"./types\"\n\n/** Rows sampled when deciding a column's format. */\nconst TYPE_SAMPLE_ROWS = 500\n\n/** Share of non-empty sampled values that must agree before a type is claimed. */\nconst TYPE_CONFIDENCE = 0.9\n\nfunction isEmpty(value: unknown): boolean {\n return value === null || value === undefined || value === \"\"\n}\n\n/**\n * `YYYY-MM-DD`, optionally with a time. XLSX hands back real `Date`s, but CSV\n * carries dates as text — recognising the ISO shape is what lets a date column\n * from a CSV align (and sort) like one. The string itself is left alone; only\n * the alignment follows from this.\n */\nconst ISO_DATE = /^\\d{4}-\\d{2}-\\d{2}(?:[T ]\\d{2}:\\d{2}(?::\\d{2})?)?$/\n\nfunction classify(value: unknown): CellFormat {\n if (value instanceof Date) return \"date\"\n if (typeof value === \"number\" && Number.isFinite(value)) return \"number\"\n if (typeof value === \"string\" && ISO_DATE.test(value)) return \"date\"\n return \"text\"\n}\n\n/**\n * Header labels are kept exactly as the file wrote them — blank stays blank,\n * and two columns titled \"Amount\" stay two columns titled \"Amount\". The viewer\n * draws this row as the file's row 1, so anything invented here (`Column 3`,\n * `Amount (2)`) would be text the reader cannot find in their own file.\n * Uniqueness lives in `key`, which is positional.\n */\nfunction toColumns(header: unknown[], width: number, body: unknown[][]): TableColumn[] {\n const columns: TableColumn[] = []\n\n for (let index = 0; index < width; index++) {\n const raw = header[index]\n const label = isEmpty(raw) ? \"\" : String(raw).trim()\n\n let numbers = 0\n let dates = 0\n let filled = 0\n for (let row = 0; row < Math.min(body.length, TYPE_SAMPLE_ROWS); row++) {\n const cell = body[row]?.[index]\n if (isEmpty(cell)) continue\n filled++\n const kind = classify(cell)\n if (kind === \"number\") numbers++\n else if (kind === \"date\") dates++\n }\n let format: CellFormat = \"text\"\n if (filled > 0) {\n if (numbers / filled >= TYPE_CONFIDENCE) format = \"number\"\n else if (dates / filled >= TYPE_CONFIDENCE) format = \"date\"\n }\n\n // The key is positional rather than derived from the label: two columns\n // titled \"Amount\" must stay distinguishable, and a label can be any text.\n // Nothing in the viewer reads it — it is there for callers rendering their\n // own table from `toSheet`.\n columns.push({ key: `c${index}`, label, format })\n }\n return columns\n}\n\n/**\n * Build a sheet from raw rows. The first row is the header — the near-universal\n * spreadsheet convention, and guessing otherwise (scoring rows for\n * \"headerness\") misfires on data that happens to start with text.\n */\nexport function toSheet(name: string, rows: unknown[][]): TableSheet {\n if (rows.length === 0) {\n return { name, columns: [], rows: [], totalRows: 0, truncated: false }\n }\n const header = rows[0] ?? []\n const body = rows.slice(1)\n const width = rows.reduce((max, row) => Math.max(max, row.length), 0)\n const truncated = body.length > FILE_PAGE_MAX_ROWS\n const kept = truncated ? body.slice(0, FILE_PAGE_MAX_ROWS) : body\n return {\n name,\n columns: toColumns(header, width, kept),\n // Pad short rows so every row has a value at every column index; ragged\n // rows are common in hand-edited CSV and would otherwise read as holes.\n rows: kept.map((row) => Array.from({ length: width }, (_, i) => row[i] ?? null)),\n totalRows: body.length,\n truncated,\n }\n}\n\nconst numberFormat = new Intl.NumberFormat()\n\n/**\n * Cell text. The raw value stays in the row so sorting compares numbers as\n * numbers and dates as dates; only the display passes through here.\n */\nexport function formatCell(value: unknown, format: CellFormat): string {\n if (isEmpty(value)) return \"\"\n // A date that arrived as text is shown exactly as the file wrote it: the\n // point of the viewer is to read the file, not to restate it.\n if (format === \"date\" && typeof value === \"string\") return value\n if (format === \"date\" && value instanceof Date) return value.toLocaleDateString()\n if (format === \"number\" && typeof value === \"number\") return numberFormat.format(value)\n if (value instanceof Date) return value.toLocaleString()\n if (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\"\n return String(value)\n}\n","/**\n * Reading a data file in the browser. Both parsers are loaded through\n * `await import()` so an app without a data-file page never ships them, and an\n * app with one only pays when such a page is opened.\n *\n * Parsing happens on the client rather than at generate time because Vantage\n * has an SPA mode (no `server/`), so there is no server to parse on — and\n * because it makes dev, `build` and `preview` run the same code over the same\n * bytes, which is what \"the same URL returns the same thing\" rests on.\n */\nimport { FILE_PAGE_MAX_BYTES } from \"../core/constants\"\nimport { toSheet } from \"./infer\"\nimport type { Workbook } from \"./types\"\n\n/** Thrown for every failure a file page can show; the page renders the message. */\nexport class FilePageError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"FilePageError\"\n }\n}\n\nfunction megabytes(bytes: number): string {\n return `${(bytes / 1024 / 1024).toFixed(1)} MB`\n}\n\n/**\n * Decode CSV bytes. A Japanese spreadsheet exported from Excel is usually\n * CP932, not UTF-8, and decoding it as UTF-8 turns every non-ASCII character\n * into U+FFFD. Rather than ask the user to declare an encoding, decode as\n * UTF-8 and fall back when the result is visibly full of replacement\n * characters — a real UTF-8 file has none.\n */\nfunction decodeCsv(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer)\n const hasBom = bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf\n const body = hasBom ? bytes.subarray(3) : bytes\n const utf8 = new TextDecoder(\"utf-8\").decode(body)\n const replacements = (utf8.match(/�/g) ?? []).length\n if (replacements > 0 && replacements / Math.max(utf8.length, 1) > 0.0005) {\n try {\n return new TextDecoder(\"shift-jis\").decode(body)\n } catch {\n // Some engines ship without the legacy decoder; the UTF-8 read is still\n // the best available answer.\n }\n }\n return utf8\n}\n\nasync function parseCsv(buffer: ArrayBuffer): Promise<Workbook> {\n const { default: Papa } = await import(\"papaparse\")\n const text = decodeCsv(buffer)\n // `header: false` on purpose: lifting the header row is done in `infer.ts`,\n // which puts CSV and XLSX on one code path instead of two.\n const result = Papa.parse<unknown[]>(text, {\n header: false,\n dynamicTyping: true,\n skipEmptyLines: \"greedy\",\n })\n return { sheets: [toSheet(\"Sheet1\", result.data)] }\n}\n\nasync function parseXlsx(buffer: ArrayBuffer): Promise<Workbook> {\n // The browser build specifically: the package has no root export, and the\n // node build reaches for `fs`.\n const { default: readXlsxFile } = await import(\"read-excel-file/browser\")\n const sheets = await readXlsxFile(buffer)\n return {\n sheets: sheets.map((sheet) => toSheet(sheet.sheet, sheet.data as unknown[][])),\n }\n}\n\n/**\n * Fetch and parse the file behind a file page. Every failure — network, size,\n * a corrupt workbook, an extension with no parser — surfaces as a rejected\n * promise so the page can render it in place instead of taking the app down.\n */\nexport async function loadWorkbook(src: string, kind: string): Promise<Workbook> {\n let buffer: ArrayBuffer\n try {\n const response = await fetch(src)\n if (!response.ok) {\n throw new FilePageError(`Could not load the file (HTTP ${response.status}).`)\n }\n buffer = await response.arrayBuffer()\n } catch (err) {\n if (err instanceof FilePageError) throw err\n throw new FilePageError(`Could not load the file: ${(err as Error).message}`)\n }\n\n if (buffer.byteLength > FILE_PAGE_MAX_BYTES) {\n throw new FilePageError(\n `This file is ${megabytes(buffer.byteLength)}, over the ${megabytes(\n FILE_PAGE_MAX_BYTES,\n )} limit for a data-file page. Download it, or serve the data from server/api/ and render it with DataTable.`,\n )\n }\n\n try {\n switch (kind) {\n case \"csv\":\n return await parseCsv(buffer)\n case \"xlsx\":\n return await parseXlsx(buffer)\n default:\n // Reached when an extension is added to FILE_PAGE_EXTENSIONS without a\n // parser here. Naming it beats rendering an empty table.\n throw new FilePageError(`No viewer for \".${kind}\" files.`)\n }\n } catch (err) {\n if (err instanceof FilePageError) throw err\n throw new FilePageError(\n `This file could not be read. It may be corrupt, password-protected, or not really a .${kind} file. (${\n (err as Error).message\n })`,\n )\n }\n}\n","/**\n * The spreadsheet grid. A data file page should read the way the file reads in\n * Excel or Sheets — column letters across the top, row numbers down the side,\n * a ruled canvas of fixed-height rows that runs past the data, and a selected\n * cell. That is why this is a grid and not a styled `DataTable`: the card, the\n * pagination and the sort affordances all say \"web table\", and none of them\n * exist in a spreadsheet.\n *\n * It is a viewer, not an editor. No toolbar, no formula bar, no editing; the\n * only interactions are moving the selection and copying a cell.\n *\n * Rows and columns are windowed. That is not an optimisation to revisit later:\n * a file page is capped at 200,000 rows, and mounting them would be hundreds of\n * thousands of DOM nodes. Fixed row height makes the window arithmetic exact,\n * so no virtualiser dependency is needed — `first = scrollTop / ROW_HEIGHT`.\n */\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n} from \"react\"\n\nimport { cn } from \"../ui/cn\"\nimport { formatCell } from \"./infer\"\nimport type { CellFormat, TableSheet } from \"./types\"\n\n/** Row height, matching a spreadsheet's default line rather than a web table's. */\nconst ROW_HEIGHT = 22\n/** Height of the A / B / C band. */\nconst HEAD_HEIGHT = 22\nconst MIN_GUTTER_WIDTH = 44\nconst MIN_COL_WIDTH = 56\nconst MAX_COL_WIDTH = 420\n/** Width of the empty columns that carry the ruling past the data. */\nconst FILLER_COL_WIDTH = 100\n/** Horizontal padding plus borders, added to the measured text width. */\nconst COL_PADDING = 18\nconst OVERSCAN_ROWS = 8\nconst OVERSCAN_COLS = 2\n/** Rows sampled when sizing a column. */\nconst WIDTH_SAMPLE_ROWS = 200\n/** Must match the cell font below, or measured widths will not fit the text. */\nconst CELL_FONT =\n '13px ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, \"Hiragino Sans\", \"Hiragino Kaku Gothic ProN\", \"Noto Sans JP\", \"Yu Gothic UI\", Meiryo, sans-serif'\n\n/** `0 → A`, `25 → Z`, `26 → AA` — spreadsheet column names. */\nexport function columnLabel(index: number): string {\n let label = \"\"\n for (let n = index; n >= 0; n = Math.floor(n / 26) - 1) {\n label = String.fromCharCode(65 + (n % 26)) + label\n }\n return label\n}\n\n/**\n * Size each column to its content, the way a spreadsheet does on import.\n * Measured with the canvas text metrics of the font the cells use, over a\n * sample spread across the whole sheet — sampling the first N rows only would\n * size a column on its header and miss the long values further down.\n */\nfunction measureWidths(sheet: TableSheet): number[] {\n const context =\n typeof document === \"undefined\" ? null : document.createElement(\"canvas\").getContext(\"2d\")\n if (context) context.font = CELL_FONT\n // Without a canvas (SSR, or a browser that refuses the context) fall back to\n // an average character width: the grid still lays out, just less snugly.\n const widthOf = (text: string) => (context ? context.measureText(text).width : text.length * 7.2)\n const stride = Math.max(1, Math.ceil(sheet.rows.length / WIDTH_SAMPLE_ROWS))\n\n return sheet.columns.map((column, index) => {\n let max = widthOf(column.label)\n for (let row = 0; row < sheet.rows.length; row += stride) {\n const text = formatCell(sheet.rows[row]?.[index], column.format)\n if (text !== \"\") max = Math.max(max, widthOf(text))\n }\n return Math.min(MAX_COL_WIDTH, Math.max(MIN_COL_WIDTH, Math.ceil(max) + COL_PADDING))\n })\n}\n\n/** Running x of each column, so windowing and scrolling are lookups. */\nfunction runningOffsets(widths: number[]): number[] {\n const offsets = [0]\n for (const width of widths) offsets.push(offsets[offsets.length - 1]! + width)\n return offsets\n}\n\n/** Index of the last offset at or before `x`. */\nfunction columnAt(offsets: number[], x: number): number {\n let low = 0\n let high = offsets.length - 2\n while (low < high) {\n const mid = (low + high + 1) >> 1\n if (offsets[mid]! <= x) low = mid\n else high = mid - 1\n }\n return Math.max(0, low)\n}\n\ninterface Selection {\n /** `0` is the header row (the file's row 1); `n` is body row `n - 1`. */\n row: number\n col: number\n}\n\nexport interface SheetGridProps {\n sheet: TableSheet\n className?: string\n}\n\n/**\n * One sheet as a grid. Fills its container, so give the parent a height —\n * `TableViewer` is the component that does that for a page.\n */\nexport function SheetGrid({ sheet, className }: SheetGridProps) {\n const scrollRef = useRef<HTMLDivElement>(null)\n const [scroll, setScroll] = useState({ top: 0, left: 0 })\n const [viewport, setViewport] = useState({ width: 0, height: 0 })\n const [selected, setSelected] = useState<Selection>({ row: 0, col: 0 })\n\n const dataWidths = useMemo(() => measureWidths(sheet), [sheet])\n const dataCols = sheet.columns.length\n const dataRows = sheet.rows.length\n\n // Wide enough for the largest row number: the gutter must not resize as the\n // window scrolls into five-digit rows.\n const gutterWidth = Math.max(MIN_GUTTER_WIDTH, String(dataRows + 1).length * 8 + 16)\n\n // Past the data the canvas keeps going, ruled and empty, as it does in every\n // spreadsheet. Enough of it to cover the viewport — beyond that nobody can\n // tell whether the sheet ends at column F or column XFD.\n const dataWidth = dataWidths.reduce((sum, width) => sum + width, 0)\n const fillerCols = Math.max(\n 0,\n Math.ceil((viewport.width - gutterWidth - dataWidth) / FILLER_COL_WIDTH),\n )\n const fillerRows = Math.max(\n 0,\n Math.ceil((viewport.height - HEAD_HEIGHT - (dataRows + 1) * ROW_HEIGHT) / ROW_HEIGHT),\n )\n const colCount = dataCols + fillerCols\n const rowCount = dataRows + fillerRows\n\n const widths = useMemo(\n () => [...dataWidths, ...Array.from({ length: fillerCols }, () => FILLER_COL_WIDTH)],\n [dataWidths, fillerCols],\n )\n const offsets = useMemo(() => runningOffsets(widths), [widths])\n const totalWidth = offsets[offsets.length - 1] ?? 0\n\n useLayoutEffect(() => {\n const element = scrollRef.current\n if (!element) return\n const measure = () => setViewport({ width: element.clientWidth, height: element.clientHeight })\n measure()\n const observer = new ResizeObserver(measure)\n observer.observe(element)\n return () => observer.disconnect()\n }, [])\n\n // Selection is positional, so a new sheet must not keep pointing at a cell\n // that no longer exists.\n useEffect(() => {\n setSelected({ row: 0, col: 0 })\n scrollRef.current?.scrollTo({ top: 0, left: 0 })\n }, [sheet])\n\n // Body rows live below the two frozen bands, so the first visible one falls\n // straight out of scrollTop.\n const firstRow = Math.max(0, Math.floor(scroll.top / ROW_HEIGHT) - OVERSCAN_ROWS)\n const lastRow = Math.min(\n rowCount,\n Math.ceil((scroll.top + viewport.height - HEAD_HEIGHT - ROW_HEIGHT) / ROW_HEIGHT) +\n OVERSCAN_ROWS,\n )\n const firstCol = Math.max(0, columnAt(offsets, scroll.left) - OVERSCAN_COLS)\n const lastCol = Math.min(\n colCount,\n columnAt(offsets, scroll.left + viewport.width) + 1 + OVERSCAN_COLS,\n )\n const leadWidth = offsets[firstCol] ?? 0\n const tailWidth = totalWidth - (offsets[lastCol] ?? totalWidth)\n const visibleCols = Array.from({ length: Math.max(0, lastCol - firstCol) }, (_, i) => firstCol + i)\n\n /** Bring a cell inside the scrollport, allowing for the frozen bands. */\n const reveal = useCallback(\n (next: Selection) => {\n const element = scrollRef.current\n if (!element) return\n if (next.row > 0) {\n const top = HEAD_HEIGHT + ROW_HEIGHT + (next.row - 1) * ROW_HEIGHT\n const frozen = HEAD_HEIGHT + ROW_HEIGHT\n if (top - element.scrollTop < frozen) element.scrollTop = top - frozen\n else if (top + ROW_HEIGHT - element.scrollTop > element.clientHeight) {\n element.scrollTop = top + ROW_HEIGHT - element.clientHeight\n }\n }\n const left = offsets[next.col] ?? 0\n const width = widths[next.col] ?? 0\n if (left - element.scrollLeft < 0) element.scrollLeft = left\n else if (left + width + gutterWidth - element.scrollLeft > element.clientWidth) {\n element.scrollLeft = left + width + gutterWidth - element.clientWidth\n }\n },\n [gutterWidth, offsets, widths],\n )\n\n const cellText = useCallback(\n (row: number, col: number): string => {\n const column = sheet.columns[col]\n if (!column) return \"\"\n if (row === 0) return column.label\n return formatCell(sheet.rows[row - 1]?.[col], column.format)\n },\n [sheet],\n )\n\n const onKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n // The selection stays on the data. The empty canvas past it is ruling,\n // not cells anyone needs to land on.\n //\n // `escapable` is what keeps this from being a keyboard trap: the grid is\n // focusable, so if Tab were always swallowed there would be no way out of\n // it. Tab that cannot move the selection any further is left to the\n // browser, which moves focus on to the sheet tabs.\n const step = (rows: number, cols: number, escapable = false) => {\n const next = {\n row: Math.min(dataRows, Math.max(0, selected.row + rows)),\n col: Math.min(dataCols - 1, Math.max(0, selected.col + cols)),\n }\n const moved = next.row !== selected.row || next.col !== selected.col\n if (moved || !escapable) event.preventDefault()\n if (!moved) return\n setSelected(next)\n reveal(next)\n }\n const page = Math.max(1, Math.floor(viewport.height / ROW_HEIGHT) - 1)\n\n switch (event.key) {\n case \"ArrowDown\":\n return step(1, 0)\n case \"ArrowUp\":\n return step(-1, 0)\n case \"Tab\":\n return step(0, event.shiftKey ? -1 : 1, true)\n case \"ArrowRight\":\n return step(0, 1)\n case \"ArrowLeft\":\n return step(0, -1)\n case \"PageDown\":\n return step(page, 0)\n case \"PageUp\":\n return step(-page, 0)\n case \"Home\":\n return step(event.ctrlKey || event.metaKey ? -dataRows : 0, -dataCols)\n case \"End\":\n return step(event.ctrlKey || event.metaKey ? dataRows : 0, dataCols)\n case \"c\":\n case \"C\":\n // The one thing a reader wants out of a viewer: the value, in full,\n // even when the column is too narrow to show it.\n if (event.metaKey || event.ctrlKey) {\n // A refused or unavailable clipboard is not worth an unhandled\n // rejection in the app's error reporting.\n navigator.clipboard?.writeText(cellText(selected.row, selected.col)).catch(() => {})\n }\n return\n default:\n return\n }\n },\n [cellText, dataCols, dataRows, reveal, selected, viewport.height],\n )\n\n if (dataCols === 0) {\n return <p className={cn(\"p-4 text-sm text-muted-foreground\", className)}>This sheet is empty.</p>\n }\n\n const select = (row: number, col: number) => {\n setSelected({ row, col })\n scrollRef.current?.focus({ preventScroll: true })\n }\n\n const rowStyle: CSSProperties = { height: ROW_HEIGHT, width: gutterWidth + totalWidth }\n\n return (\n <div\n ref={scrollRef}\n role=\"grid\"\n aria-label={sheet.name}\n aria-rowcount={dataRows + 1}\n aria-colcount={dataCols}\n tabIndex={0}\n onScroll={(event) =>\n setScroll({ top: event.currentTarget.scrollTop, left: event.currentTarget.scrollLeft })\n }\n onKeyDown={onKeyDown}\n className={cn(\n \"relative h-full overflow-auto bg-background text-[13px] outline-none select-none [overscroll-behavior:contain]\",\n className,\n )}\n >\n <div role=\"rowgroup\" style={{ width: gutterWidth + totalWidth }}>\n {/* A / B / C. Sticky on both axes, so the corner stays put. */}\n <div\n className=\"sticky top-0 z-40 flex\"\n style={{ ...rowStyle, height: HEAD_HEIGHT }}\n role=\"row\"\n >\n <div\n className=\"sticky left-0 z-10 shrink-0 border-r border-b border-border bg-muted\"\n style={{ width: gutterWidth, height: HEAD_HEIGHT }}\n />\n <div className=\"shrink-0 border-b border-border bg-muted\" style={{ width: leadWidth }} />\n {visibleCols.map((col) => (\n <div\n key={col}\n role={col < dataCols ? \"columnheader\" : \"presentation\"}\n aria-colindex={col < dataCols ? col + 1 : undefined}\n onMouseDown={col < dataCols ? () => select(selected.row, col) : undefined}\n className={cn(\n \"flex shrink-0 items-center justify-center border-r border-b border-border bg-muted text-[11px] text-muted-foreground\",\n selected.col === col && col < dataCols && \"bg-accent font-medium text-foreground\",\n )}\n style={{ width: widths[col], height: HEAD_HEIGHT }}\n >\n {columnLabel(col)}\n </div>\n ))}\n <div className=\"shrink-0 border-b border-border bg-muted\" style={{ width: tailWidth }} />\n </div>\n\n {/* The file's row 1. Frozen under the letters, because a data file's\n first row is its header and reading row 40,000 without it is\n guesswork — the first thing anyone does to a sheet by hand. */}\n {/* Opaque: body rows scroll underneath this one. */}\n <div\n className=\"sticky z-30 flex bg-background\"\n style={{ ...rowStyle, top: HEAD_HEIGHT }}\n role=\"row\"\n >\n <RowHeader\n label=\"1\"\n width={gutterWidth}\n active={selected.row === 0}\n onSelect={() => select(0, selected.col)}\n />\n <div className=\"shrink-0 border-b border-foreground/25\" style={{ width: leadWidth }} />\n {visibleCols.map((col) => (\n <Cell\n key={col}\n width={widths[col]!}\n // A header label is text, and a spreadsheet aligns a cell by what\n // is in it — so it reads left even over a column of numbers.\n format=\"text\"\n text={sheet.columns[col]?.label ?? \"\"}\n header\n selected={selected.row === 0 && selected.col === col}\n onSelect={col < dataCols ? () => select(0, col) : undefined}\n colIndex={col < dataCols ? col : undefined}\n />\n ))}\n <div className=\"shrink-0 border-b border-foreground/25\" style={{ width: tailWidth }} />\n </div>\n\n {/* `presentation` so the rows below stay owned by the rowgroup above. */}\n <div role=\"presentation\" className=\"relative\" style={{ height: rowCount * ROW_HEIGHT }}>\n {Array.from({ length: Math.max(0, lastRow - firstRow) }, (_, offset) => {\n const row = firstRow + offset\n const cells = sheet.rows[row]\n return (\n <div\n key={row}\n role=\"row\"\n aria-rowindex={row < dataRows ? row + 2 : undefined}\n className=\"absolute flex\"\n style={{ ...rowStyle, top: row * ROW_HEIGHT }}\n >\n <RowHeader\n label={String(row + 2)}\n width={gutterWidth}\n active={selected.row === row + 1}\n onSelect={row < dataRows ? () => select(row + 1, selected.col) : undefined}\n />\n <div className=\"shrink-0\" style={{ width: leadWidth }} />\n {visibleCols.map((col) => {\n const column = sheet.columns[col]\n return (\n <Cell\n key={col}\n width={widths[col]!}\n format={column?.format ?? \"text\"}\n text={column ? formatCell(cells?.[col], column.format) : \"\"}\n selected={selected.row === row + 1 && selected.col === col}\n onSelect={\n row < dataRows && col < dataCols ? () => select(row + 1, col) : undefined\n }\n colIndex={col < dataCols ? col : undefined}\n />\n )\n })}\n <div className=\"shrink-0\" style={{ width: tailWidth }} />\n </div>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\nSheetGrid.displayName = \"SheetGrid\"\n\nfunction RowHeader({\n label,\n width,\n active,\n onSelect,\n}: {\n label: string\n width: number\n active: boolean\n onSelect?: () => void\n}) {\n return (\n <div\n role={onSelect ? \"rowheader\" : \"presentation\"}\n onMouseDown={onSelect}\n className={cn(\n // Above a selected cell (`z-10`): scrolling a selected column under the\n // gutter must not paint its outline over the row number.\n \"sticky left-0 z-20 flex h-full shrink-0 items-center justify-center border-r border-b border-border bg-muted text-[11px] text-muted-foreground\",\n active && \"bg-accent font-medium text-foreground\",\n )}\n style={{ width }}\n >\n {label}\n </div>\n )\n}\n\nfunction Cell({\n width,\n format,\n text,\n header,\n selected,\n onSelect,\n colIndex,\n}: {\n width: number\n format: CellFormat\n text: string\n header?: boolean\n selected: boolean\n onSelect?: () => void\n colIndex?: number\n}) {\n return (\n <div\n role={onSelect ? \"gridcell\" : \"presentation\"}\n aria-colindex={colIndex === undefined ? undefined : colIndex + 1}\n aria-selected={onSelect ? selected : undefined}\n onMouseDown={onSelect}\n // Columns are sized to their content but capped, so a long value still\n // gets clipped — the title is how the rest of it stays reachable\n // without a formula bar.\n title={text || undefined}\n className={cn(\n \"flex h-full shrink-0 items-center border-r border-b border-border px-1.5\",\n header && \"border-b-foreground/25 font-medium\",\n // Numbers and dates read right-aligned, as they do in a spreadsheet.\n format === \"text\" ? \"justify-start\" : \"justify-end tabular-nums\",\n selected && onSelect && \"relative z-10 outline-2 -outline-offset-2 outline-primary\",\n )}\n style={{ width }}\n >\n <span className=\"truncate\">{text}</span>\n </div>\n )\n}\n","/**\n * One sheet, framed the way a spreadsheet application frames one: the grid\n * fills the window, and a status bar sits under it with the sheet tabs on the\n * left and the shape of the sheet on the right.\n *\n * The frame is what makes the grid usable — a grid needs a definite height to\n * scroll inside, and a Vantage page has no guaranteed one (layouts belong to\n * the app). So it measures the space left below itself in the viewport rather\n * than asking the app to arrange for a height.\n */\nimport { useLayoutEffect, useRef, useState, type RefObject } from \"react\"\n\nimport { cn } from \"../ui/cn\"\nimport { SheetGrid } from \"./sheet-grid\"\nimport type { TableSheet } from \"./types\"\n\n/** Never collapse below this, however little viewport is left. */\nconst MIN_HEIGHT = 320\n/** Breathing room under the frame when the layout leaves none of its own. */\nconst MIN_BOTTOM_GAP = 8\n\nexport interface TableViewerProps {\n /** The sheet to render. */\n sheet: TableSheet\n /** Every sheet's name. Given more than one, a tab strip is rendered. */\n sheetNames?: string[]\n activeSheet?: number\n onSheetChange?: (index: number) => void\n /**\n * Fixed height for the frame. Without it the viewer fills the rest of the\n * viewport, which is right for a file page and wrong for a table embedded in\n * a dashboard among other cards.\n */\n height?: number | string\n className?: string\n}\n\n/**\n * What the layout keeps under the frame: every ancestor's bottom padding,\n * border and margin. It has to come out of the height, or the page ends up\n * scrollable by exactly that much (a page shell nested in a layout shell means\n * two lots of padding). Read from the box model rather than from the document\n * height, which a `min-h-screen` layout pins to the viewport and would make\n * this feed back on its own result.\n */\nfunction spaceBelow(element: HTMLElement): number {\n let total = 0\n for (let node = element.parentElement; node && node !== document.body; node = node.parentElement) {\n const style = getComputedStyle(node)\n total +=\n parseFloat(style.paddingBottom) + parseFloat(style.borderBottomWidth) + parseFloat(style.marginBottom)\n }\n return Number.isFinite(total) ? total : 0\n}\n\n/**\n * Fill the rest of the viewport. Measured rather than expressed in CSS: the\n * frame's distance from the top of the window depends on whatever the app's\n * layout put above it, which no `calc()` here can know.\n */\nfunction useFillHeight(ref: RefObject<HTMLElement | null>, enabled: boolean): number {\n const [height, setHeight] = useState(MIN_HEIGHT)\n\n useLayoutEffect(() => {\n const element = ref.current\n if (!element || !enabled) return\n const measure = () => {\n // Document-relative, not viewport-relative: `rect.top` alone shrinks as\n // the page scrolls, so a measurement taken while scrolled (a mobile URL\n // bar collapsing fires `resize`) would make the frame taller than the\n // viewport and add page scroll that never goes away.\n const rect = element.getBoundingClientRect()\n const top = rect.top + window.scrollY\n const next = Math.max(\n MIN_HEIGHT,\n window.innerHeight - top - Math.max(spaceBelow(element), MIN_BOTTOM_GAP),\n )\n // Only a real change: the frame's own height feeds back into the\n // document height, and rounding noise would loop.\n setHeight((current) => (Math.abs(current - next) > 1 ? next : current))\n }\n measure()\n const observer = new ResizeObserver(measure)\n observer.observe(document.body)\n window.addEventListener(\"resize\", measure)\n return () => {\n observer.disconnect()\n window.removeEventListener(\"resize\", measure)\n }\n }, [enabled, ref])\n\n return height\n}\n\nfunction plural(count: number, noun: string): string {\n return `${count.toLocaleString()} ${noun}${count === 1 ? \"\" : \"s\"}`\n}\n\n/** Render one parsed sheet. Exported so an app can drive it with its own data. */\nexport function TableViewer({\n sheet,\n sheetNames,\n activeSheet = 0,\n onSheetChange,\n height,\n className,\n}: TableViewerProps) {\n const frameRef = useRef<HTMLDivElement>(null)\n const filled = useFillHeight(frameRef, height === undefined)\n const tabs = sheetNames && sheetNames.length > 1 ? sheetNames : null\n\n return (\n <div\n ref={frameRef}\n className={cn(\n \"flex flex-col overflow-hidden rounded-md border border-border bg-background\",\n className,\n )}\n style={{ height: height ?? filled }}\n >\n <div className=\"min-h-0 flex-1\">\n <SheetGrid sheet={sheet} />\n </div>\n\n {/* The status bar: sheet tabs and the shape of the sheet, where a\n spreadsheet puts them. */}\n <div className=\"flex items-center gap-4 border-t border-border bg-muted/60 px-2 py-1\">\n {tabs ? (\n <div className=\"flex min-w-0 items-end gap-px overflow-x-auto\" role=\"tablist\">\n {tabs.map((name, index) => (\n <button\n key={name}\n type=\"button\"\n role=\"tab\"\n aria-selected={index === activeSheet}\n onClick={() => onSheetChange?.(index)}\n className={cn(\n \"shrink-0 rounded-t-sm border-t-2 px-3 py-1 text-xs whitespace-nowrap\",\n index === activeSheet\n ? \"border-primary bg-background font-medium text-foreground\"\n : \"border-transparent text-muted-foreground hover:text-foreground\",\n )}\n >\n {name}\n </button>\n ))}\n </div>\n ) : null}\n\n <div className=\"ml-auto flex shrink-0 items-center gap-3 text-[11px] text-muted-foreground\">\n {sheet.truncated ? (\n <span className=\"font-medium text-foreground\">\n First {sheet.rows.length.toLocaleString()} of {sheet.totalRows.toLocaleString()} rows —\n download the file for the rest\n </span>\n ) : null}\n <span>\n {plural(sheet.totalRows, \"row\")} × {plural(sheet.columns.length, \"column\")}\n </span>\n </div>\n </div>\n </div>\n )\n}\nTableViewer.displayName = \"TableViewer\"\n","/**\n * The page a `.csv` or `.xlsx` under `src/` becomes. Generated wrappers in\n * `.vantage/file-pages/` mount this; apps can mount it themselves to take over\n * the title or to render a file kept out of routing with an `_` prefix.\n */\nimport { useState } from \"react\"\nimport { DownloadIcon } from \"lucide-react\"\nimport {\n PageShell,\n PageShellActions,\n PageShellContent,\n PageShellHeader,\n PageShellHeading,\n PageShellMeta,\n PageShellTitle,\n} from \"../components\"\nimport { useQuery } from \"../query\"\nimport { Button } from \"../ui/button\"\nimport { Loading, ErrorState } from \"../ui/states\"\nimport { loadWorkbook } from \"./parse\"\nimport { TableViewer } from \"./table-viewer\"\n\nexport interface FilePageViewProps {\n /** Extension without the dot, e.g. `\"xlsx\"`. */\n kind: string\n /** URL of the file, produced by Vite's asset pipeline. */\n src: string\n /** Original file name, used for the heading fallback and the download. */\n fileName: string\n /** Title derived from the file name at generate time. */\n title?: string\n}\n\nexport function FilePageView({ kind, src, fileName, title }: FilePageViewProps) {\n const [active, setActive] = useState(0)\n\n // The framework's QueryClient is already above this in the tree, so the\n // parsed workbook is cached across navigations for free and the retry and\n // networkMode policies are the managed ones — no second provider.\n const workbook = useQuery({\n queryKey: [\"vantage:file-page\", src],\n queryFn: () => loadWorkbook(src, kind),\n staleTime: Infinity,\n })\n\n const download = (\n // `nativeButton={false}` because this renders an `<a>`: Base UI needs to\n // know it is not driving a real button, or it warns and keeps button\n // semantics that would fight the link's.\n <Button\n variant=\"outline\"\n size=\"sm\"\n nativeButton={false}\n render={<a href={src} download={fileName} />}\n >\n <DownloadIcon aria-hidden=\"true\" />\n Download\n </Button>\n )\n\n const sheets = workbook.data?.sheets ?? []\n const sheet = sheets[Math.min(active, Math.max(sheets.length - 1, 0))]\n\n return (\n <PageShell>\n {/* A slim band: the grid below wants the vertical room, and a data file\n has no description to carry. */}\n <PageShellHeader className=\"py-6\">\n <PageShellHeading>\n <PageShellTitle>{title ?? fileName}</PageShellTitle>\n <PageShellMeta>{fileName}</PageShellMeta>\n </PageShellHeading>\n <PageShellActions>{download}</PageShellActions>\n </PageShellHeader>\n\n <PageShellContent>\n {workbook.isPending ? <Loading label={`Reading ${fileName}…`} /> : null}\n\n {/* Every failure path lands here, inside the page. A data file the\n browser cannot read must not take the rest of the app down. */}\n {workbook.isError ? (\n <ErrorState\n title={`Could not display ${fileName}`}\n message={(workbook.error as Error).message}\n action={download}\n />\n ) : null}\n\n {sheet ? (\n <TableViewer\n sheet={sheet}\n sheetNames={sheets.map((s) => s.name)}\n activeSheet={active}\n onSheetChange={setActive}\n />\n ) : null}\n </PageShellContent>\n </PageShell>\n )\n}\nFilePageView.displayName = \"FilePageView\"\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/table/infer.ts","../../src/table/parse.ts","../../src/table/sheet-grid.tsx","../../src/table/table-viewer.tsx","../../src/table/file-page-view.tsx"],"names":["useState","useLayoutEffect","useRef","jsxs","jsx"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Turning raw rows into a readable table: which row is the header, what each\n * column holds, and how a cell should read. Deliberately shallow — the goal is\n * \"legible as a spreadsheet\", not a reimplementation of one. Formulas, charts\n * and cell formatting are dropped; their values are what survive.\n */\nimport { FILE_PAGE_MAX_ROWS } from \"../core/constants\"\nimport type { CellFormat, TableColumn, TableSheet } from \"./types\"\n\n/** Rows sampled when deciding a column's format. */\nconst TYPE_SAMPLE_ROWS = 500\n\n/** Share of non-empty sampled values that must agree before a type is claimed. */\nconst TYPE_CONFIDENCE = 0.9\n\nfunction isEmpty(value: unknown): boolean {\n return value === null || value === undefined || value === \"\"\n}\n\n/**\n * `YYYY-MM-DD`, optionally with a time. XLSX hands back real `Date`s, but CSV\n * carries dates as text — recognising the ISO shape is what lets a date column\n * from a CSV align (and sort) like one. The string itself is left alone; only\n * the alignment follows from this.\n */\nconst ISO_DATE = /^\\d{4}-\\d{2}-\\d{2}(?:[T ]\\d{2}:\\d{2}(?::\\d{2})?)?$/\n\nfunction classify(value: unknown): CellFormat {\n if (value instanceof Date) return \"date\"\n if (typeof value === \"number\" && Number.isFinite(value)) return \"number\"\n if (typeof value === \"string\" && ISO_DATE.test(value)) return \"date\"\n return \"text\"\n}\n\n/**\n * Header labels are kept exactly as the file wrote them — blank stays blank,\n * and two columns titled \"Amount\" stay two columns titled \"Amount\". The viewer\n * draws this row as the file's row 1, so anything invented here (`Column 3`,\n * `Amount (2)`) would be text the reader cannot find in their own file.\n * Uniqueness lives in `key`, which is positional.\n */\nfunction toColumns(header: unknown[], width: number, body: unknown[][]): TableColumn[] {\n const columns: TableColumn[] = []\n\n for (let index = 0; index < width; index++) {\n const raw = header[index]\n const label = isEmpty(raw) ? \"\" : String(raw).trim()\n\n let numbers = 0\n let dates = 0\n let filled = 0\n for (let row = 0; row < Math.min(body.length, TYPE_SAMPLE_ROWS); row++) {\n const cell = body[row]?.[index]\n if (isEmpty(cell)) continue\n filled++\n const kind = classify(cell)\n if (kind === \"number\") numbers++\n else if (kind === \"date\") dates++\n }\n let format: CellFormat = \"text\"\n if (filled > 0) {\n if (numbers / filled >= TYPE_CONFIDENCE) format = \"number\"\n else if (dates / filled >= TYPE_CONFIDENCE) format = \"date\"\n }\n\n // The key is positional rather than derived from the label: two columns\n // titled \"Amount\" must stay distinguishable, and a label can be any text.\n // Nothing in the viewer reads it — it is there for callers rendering their\n // own table from `toSheet`.\n columns.push({ key: `c${index}`, label, format })\n }\n return columns\n}\n\n/**\n * Build a sheet from raw rows. The first row is the header — the near-universal\n * spreadsheet convention, and guessing otherwise (scoring rows for\n * \"headerness\") misfires on data that happens to start with text.\n */\nexport function toSheet(name: string, rows: unknown[][]): TableSheet {\n if (rows.length === 0) {\n return { name, columns: [], rows: [], totalRows: 0, truncated: false }\n }\n const header = rows[0] ?? []\n const body = rows.slice(1)\n const width = rows.reduce((max, row) => Math.max(max, row.length), 0)\n const truncated = body.length > FILE_PAGE_MAX_ROWS\n const kept = truncated ? body.slice(0, FILE_PAGE_MAX_ROWS) : body\n return {\n name,\n columns: toColumns(header, width, kept),\n // Pad short rows so every row has a value at every column index; ragged\n // rows are common in hand-edited CSV and would otherwise read as holes.\n rows: kept.map((row) => Array.from({ length: width }, (_, i) => row[i] ?? null)),\n totalRows: body.length,\n truncated,\n }\n}\n\nconst numberFormat = new Intl.NumberFormat()\n\n/**\n * XLSX dates have no time zone: read-excel-file turns the serial number into\n * a `Date` whose UTC fields hold the wall-clock value the file shows\n * (2026-06-02 → 2026-06-02T00:00:00Z). Formatting in the browser's zone would\n * move it — a day early west of UTC, an evening time into the next day east\n * of it — so it is always read in UTC. The raw `Date` is left as is, so\n * comparing two of them still orders them as the file does.\n */\nconst WALL_CLOCK = { timeZone: \"UTC\" } as const\n\n/**\n * Cell text. The raw value stays in the row so sorting compares numbers as\n * numbers and dates as dates; only the display passes through here.\n */\nexport function formatCell(value: unknown, format: CellFormat): string {\n if (isEmpty(value)) return \"\"\n // A date that arrived as text is shown exactly as the file wrote it: the\n // point of the viewer is to read the file, not to restate it.\n if (format === \"date\" && typeof value === \"string\") return value\n if (format === \"date\" && value instanceof Date) return value.toLocaleDateString(undefined, WALL_CLOCK)\n if (format === \"number\" && typeof value === \"number\") return numberFormat.format(value)\n if (value instanceof Date) return value.toLocaleString(undefined, WALL_CLOCK)\n if (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\"\n return String(value)\n}\n","/**\n * Reading a data file in the browser. Both parsers are loaded through\n * `await import()` so an app without a data-file page never ships them, and an\n * app with one only pays when such a page is opened.\n *\n * Parsing happens on the client rather than at generate time because Vantage\n * has an SPA mode (no `server/`), so there is no server to parse on — and\n * because it makes dev, `build` and `preview` run the same code over the same\n * bytes, which is what \"the same URL returns the same thing\" rests on.\n */\nimport { FILE_PAGE_MAX_BYTES } from \"../core/constants\"\nimport { toSheet } from \"./infer\"\nimport type { Workbook } from \"./types\"\n\n/** Thrown for every failure a file page can show; the page renders the message. */\nexport class FilePageError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"FilePageError\"\n }\n}\n\nfunction megabytes(bytes: number): string {\n return `${(bytes / 1024 / 1024).toFixed(1)} MB`\n}\n\n/**\n * Decode CSV bytes. A Japanese spreadsheet exported from Excel is usually\n * CP932, not UTF-8, and decoding it as UTF-8 turns every non-ASCII character\n * into U+FFFD. Rather than ask the user to declare an encoding, decode as\n * UTF-8 and fall back when the result is visibly full of replacement\n * characters — a real UTF-8 file has none.\n */\nfunction decodeCsv(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer)\n const hasBom = bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf\n const body = hasBom ? bytes.subarray(3) : bytes\n const utf8 = new TextDecoder(\"utf-8\").decode(body)\n const replacements = (utf8.match(/�/g) ?? []).length\n if (replacements > 0 && replacements / Math.max(utf8.length, 1) > 0.0005) {\n try {\n return new TextDecoder(\"shift-jis\").decode(body)\n } catch {\n // Some engines ship without the legacy decoder; the UTF-8 read is still\n // the best available answer.\n }\n }\n return utf8\n}\n\nasync function parseCsv(buffer: ArrayBuffer): Promise<Workbook> {\n const { default: Papa } = await import(\"papaparse\")\n const text = decodeCsv(buffer)\n // `header: false` on purpose: lifting the header row is done in `infer.ts`,\n // which puts CSV and XLSX on one code path instead of two.\n const result = Papa.parse<unknown[]>(text, {\n header: false,\n dynamicTyping: true,\n skipEmptyLines: \"greedy\",\n })\n return { sheets: [toSheet(\"Sheet1\", result.data)] }\n}\n\nasync function parseXlsx(buffer: ArrayBuffer): Promise<Workbook> {\n // The browser build specifically: the package has no root export, and the\n // node build reaches for `fs`.\n const { default: readXlsxFile } = await import(\"read-excel-file/browser\")\n const sheets = await readXlsxFile(buffer)\n return {\n sheets: sheets.map((sheet) => toSheet(sheet.sheet, sheet.data as unknown[][])),\n }\n}\n\n/**\n * Fetch and parse the file behind a file page. Every failure — network, size,\n * a corrupt workbook, an extension with no parser — surfaces as a rejected\n * promise so the page can render it in place instead of taking the app down.\n */\nexport async function loadWorkbook(src: string, kind: string): Promise<Workbook> {\n let buffer: ArrayBuffer\n try {\n const response = await fetch(src)\n if (!response.ok) {\n throw new FilePageError(`Could not load the file (HTTP ${response.status}).`)\n }\n buffer = await response.arrayBuffer()\n } catch (err) {\n if (err instanceof FilePageError) throw err\n throw new FilePageError(`Could not load the file: ${(err as Error).message}`)\n }\n\n if (buffer.byteLength > FILE_PAGE_MAX_BYTES) {\n throw new FilePageError(\n `This file is ${megabytes(buffer.byteLength)}, over the ${megabytes(\n FILE_PAGE_MAX_BYTES,\n )} limit for a data-file page. Download it, or serve the data from server/api/ and render it with DataTable.`,\n )\n }\n\n try {\n switch (kind) {\n case \"csv\":\n return await parseCsv(buffer)\n case \"xlsx\":\n return await parseXlsx(buffer)\n default:\n // Reached when an extension is added to FILE_PAGE_EXTENSIONS without a\n // parser here. Naming it beats rendering an empty table.\n throw new FilePageError(`No viewer for \".${kind}\" files.`)\n }\n } catch (err) {\n if (err instanceof FilePageError) throw err\n throw new FilePageError(\n `This file could not be read. It may be corrupt, password-protected, or not really a .${kind} file. (${\n (err as Error).message\n })`,\n )\n }\n}\n","/**\n * The spreadsheet grid. A data file page should read the way the file reads in\n * Excel or Sheets — column letters across the top, row numbers down the side,\n * a ruled canvas of fixed-height rows that runs past the data, and a selected\n * cell. That is why this is a grid and not a styled `DataTable`: the card, the\n * pagination and the sort affordances all say \"web table\", and none of them\n * exist in a spreadsheet.\n *\n * It is a viewer, not an editor. No toolbar, no formula bar, no editing; the\n * only interactions are moving the selection and copying a cell.\n *\n * Rows and columns are windowed. That is not an optimisation to revisit later:\n * a file page is capped at 200,000 rows, and mounting them would be hundreds of\n * thousands of DOM nodes. Fixed row height makes the window arithmetic exact,\n * so no virtualiser dependency is needed — `first = scrollTop / ROW_HEIGHT`.\n */\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n} from \"react\"\n\nimport { cn } from \"../ui/cn\"\nimport { formatCell } from \"./infer\"\nimport type { CellFormat, TableSheet } from \"./types\"\n\n/** Row height, matching a spreadsheet's default line rather than a web table's. */\nconst ROW_HEIGHT = 22\n/** Height of the A / B / C band. */\nconst HEAD_HEIGHT = 22\nconst MIN_GUTTER_WIDTH = 44\nconst MIN_COL_WIDTH = 56\nconst MAX_COL_WIDTH = 420\n/** Width of the empty columns that carry the ruling past the data. */\nconst FILLER_COL_WIDTH = 100\n/** Horizontal padding plus borders, added to the measured text width. */\nconst COL_PADDING = 18\nconst OVERSCAN_ROWS = 8\nconst OVERSCAN_COLS = 2\n/** Rows sampled when sizing a column. */\nconst WIDTH_SAMPLE_ROWS = 200\n/** Must match the cell font below, or measured widths will not fit the text. */\nconst CELL_FONT =\n '13px ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, \"Hiragino Sans\", \"Hiragino Kaku Gothic ProN\", \"Noto Sans JP\", \"Yu Gothic UI\", Meiryo, sans-serif'\n\n/** `0 → A`, `25 → Z`, `26 → AA` — spreadsheet column names. */\nexport function columnLabel(index: number): string {\n let label = \"\"\n for (let n = index; n >= 0; n = Math.floor(n / 26) - 1) {\n label = String.fromCharCode(65 + (n % 26)) + label\n }\n return label\n}\n\n/**\n * Size each column to its content, the way a spreadsheet does on import.\n * Measured with the canvas text metrics of the font the cells use, over a\n * sample spread across the whole sheet — sampling the first N rows only would\n * size a column on its header and miss the long values further down.\n */\nfunction measureWidths(sheet: TableSheet): number[] {\n const context =\n typeof document === \"undefined\" ? null : document.createElement(\"canvas\").getContext(\"2d\")\n if (context) context.font = CELL_FONT\n // Without a canvas (SSR, or a browser that refuses the context) fall back to\n // an average character width: the grid still lays out, just less snugly.\n const widthOf = (text: string) => (context ? context.measureText(text).width : text.length * 7.2)\n const stride = Math.max(1, Math.ceil(sheet.rows.length / WIDTH_SAMPLE_ROWS))\n\n return sheet.columns.map((column, index) => {\n let max = widthOf(column.label)\n for (let row = 0; row < sheet.rows.length; row += stride) {\n const text = formatCell(sheet.rows[row]?.[index], column.format)\n if (text !== \"\") max = Math.max(max, widthOf(text))\n }\n return Math.min(MAX_COL_WIDTH, Math.max(MIN_COL_WIDTH, Math.ceil(max) + COL_PADDING))\n })\n}\n\n/** Running x of each column, so windowing and scrolling are lookups. */\nfunction runningOffsets(widths: number[]): number[] {\n const offsets = [0]\n for (const width of widths) offsets.push(offsets[offsets.length - 1]! + width)\n return offsets\n}\n\n/** Index of the last offset at or before `x`. */\nfunction columnAt(offsets: number[], x: number): number {\n let low = 0\n let high = offsets.length - 2\n while (low < high) {\n const mid = (low + high + 1) >> 1\n if (offsets[mid]! <= x) low = mid\n else high = mid - 1\n }\n return Math.max(0, low)\n}\n\ninterface Selection {\n /** `0` is the header row (the file's row 1); `n` is body row `n - 1`. */\n row: number\n col: number\n}\n\nexport interface SheetGridProps {\n sheet: TableSheet\n className?: string\n}\n\n/**\n * One sheet as a grid. Fills its container, so give the parent a height —\n * `TableViewer` is the component that does that for a page.\n */\nexport function SheetGrid({ sheet, className }: SheetGridProps) {\n const scrollRef = useRef<HTMLDivElement>(null)\n const [scroll, setScroll] = useState({ top: 0, left: 0 })\n const [viewport, setViewport] = useState({ width: 0, height: 0 })\n const [selected, setSelected] = useState<Selection>({ row: 0, col: 0 })\n\n const dataWidths = useMemo(() => measureWidths(sheet), [sheet])\n const dataCols = sheet.columns.length\n const dataRows = sheet.rows.length\n\n // Wide enough for the largest row number: the gutter must not resize as the\n // window scrolls into five-digit rows.\n const gutterWidth = Math.max(MIN_GUTTER_WIDTH, String(dataRows + 1).length * 8 + 16)\n\n // Past the data the canvas keeps going, ruled and empty, as it does in every\n // spreadsheet. Enough of it to cover the viewport — beyond that nobody can\n // tell whether the sheet ends at column F or column XFD.\n const dataWidth = dataWidths.reduce((sum, width) => sum + width, 0)\n const fillerCols = Math.max(\n 0,\n Math.ceil((viewport.width - gutterWidth - dataWidth) / FILLER_COL_WIDTH),\n )\n const fillerRows = Math.max(\n 0,\n Math.ceil((viewport.height - HEAD_HEIGHT - (dataRows + 1) * ROW_HEIGHT) / ROW_HEIGHT),\n )\n const colCount = dataCols + fillerCols\n const rowCount = dataRows + fillerRows\n\n const widths = useMemo(\n () => [...dataWidths, ...Array.from({ length: fillerCols }, () => FILLER_COL_WIDTH)],\n [dataWidths, fillerCols],\n )\n const offsets = useMemo(() => runningOffsets(widths), [widths])\n const totalWidth = offsets[offsets.length - 1] ?? 0\n\n useLayoutEffect(() => {\n const element = scrollRef.current\n if (!element) return\n const measure = () => setViewport({ width: element.clientWidth, height: element.clientHeight })\n measure()\n const observer = new ResizeObserver(measure)\n observer.observe(element)\n return () => observer.disconnect()\n }, [])\n\n // Selection is positional, so a new sheet must not keep pointing at a cell\n // that no longer exists.\n useEffect(() => {\n setSelected({ row: 0, col: 0 })\n scrollRef.current?.scrollTo({ top: 0, left: 0 })\n }, [sheet])\n\n // Body rows live below the two frozen bands, so the first visible one falls\n // straight out of scrollTop.\n const firstRow = Math.max(0, Math.floor(scroll.top / ROW_HEIGHT) - OVERSCAN_ROWS)\n const lastRow = Math.min(\n rowCount,\n Math.ceil((scroll.top + viewport.height - HEAD_HEIGHT - ROW_HEIGHT) / ROW_HEIGHT) +\n OVERSCAN_ROWS,\n )\n const firstCol = Math.max(0, columnAt(offsets, scroll.left) - OVERSCAN_COLS)\n const lastCol = Math.min(\n colCount,\n columnAt(offsets, scroll.left + viewport.width) + 1 + OVERSCAN_COLS,\n )\n const leadWidth = offsets[firstCol] ?? 0\n const tailWidth = totalWidth - (offsets[lastCol] ?? totalWidth)\n const visibleCols = Array.from({ length: Math.max(0, lastCol - firstCol) }, (_, i) => firstCol + i)\n\n /** Bring a cell inside the scrollport, allowing for the frozen bands. */\n const reveal = useCallback(\n (next: Selection) => {\n const element = scrollRef.current\n if (!element) return\n if (next.row > 0) {\n const top = HEAD_HEIGHT + ROW_HEIGHT + (next.row - 1) * ROW_HEIGHT\n const frozen = HEAD_HEIGHT + ROW_HEIGHT\n if (top - element.scrollTop < frozen) element.scrollTop = top - frozen\n else if (top + ROW_HEIGHT - element.scrollTop > element.clientHeight) {\n element.scrollTop = top + ROW_HEIGHT - element.clientHeight\n }\n }\n const left = offsets[next.col] ?? 0\n const width = widths[next.col] ?? 0\n if (left - element.scrollLeft < 0) element.scrollLeft = left\n else if (left + width + gutterWidth - element.scrollLeft > element.clientWidth) {\n element.scrollLeft = left + width + gutterWidth - element.clientWidth\n }\n },\n [gutterWidth, offsets, widths],\n )\n\n const cellText = useCallback(\n (row: number, col: number): string => {\n const column = sheet.columns[col]\n if (!column) return \"\"\n if (row === 0) return column.label\n return formatCell(sheet.rows[row - 1]?.[col], column.format)\n },\n [sheet],\n )\n\n const onKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n // The selection stays on the data. The empty canvas past it is ruling,\n // not cells anyone needs to land on.\n //\n // `escapable` is what keeps this from being a keyboard trap: the grid is\n // focusable, so if Tab were always swallowed there would be no way out of\n // it. Tab that cannot move the selection any further is left to the\n // browser, which moves focus on to the sheet tabs.\n const step = (rows: number, cols: number, escapable = false) => {\n const next = {\n row: Math.min(dataRows, Math.max(0, selected.row + rows)),\n col: Math.min(dataCols - 1, Math.max(0, selected.col + cols)),\n }\n const moved = next.row !== selected.row || next.col !== selected.col\n if (moved || !escapable) event.preventDefault()\n if (!moved) return\n setSelected(next)\n reveal(next)\n }\n const page = Math.max(1, Math.floor(viewport.height / ROW_HEIGHT) - 1)\n\n switch (event.key) {\n case \"ArrowDown\":\n return step(1, 0)\n case \"ArrowUp\":\n return step(-1, 0)\n case \"Tab\":\n return step(0, event.shiftKey ? -1 : 1, true)\n case \"ArrowRight\":\n return step(0, 1)\n case \"ArrowLeft\":\n return step(0, -1)\n case \"PageDown\":\n return step(page, 0)\n case \"PageUp\":\n return step(-page, 0)\n case \"Home\":\n return step(event.ctrlKey || event.metaKey ? -dataRows : 0, -dataCols)\n case \"End\":\n return step(event.ctrlKey || event.metaKey ? dataRows : 0, dataCols)\n case \"c\":\n case \"C\":\n // The one thing a reader wants out of a viewer: the value, in full,\n // even when the column is too narrow to show it.\n if (event.metaKey || event.ctrlKey) {\n // A refused or unavailable clipboard is not worth an unhandled\n // rejection in the app's error reporting.\n navigator.clipboard?.writeText(cellText(selected.row, selected.col)).catch(() => {})\n }\n return\n default:\n return\n }\n },\n [cellText, dataCols, dataRows, reveal, selected, viewport.height],\n )\n\n if (dataCols === 0) {\n return <p className={cn(\"p-4 text-sm text-muted-foreground\", className)}>This sheet is empty.</p>\n }\n\n const select = (row: number, col: number) => {\n setSelected({ row, col })\n scrollRef.current?.focus({ preventScroll: true })\n }\n\n const rowStyle: CSSProperties = { height: ROW_HEIGHT, width: gutterWidth + totalWidth }\n\n return (\n <div\n ref={scrollRef}\n role=\"grid\"\n aria-label={sheet.name}\n aria-rowcount={dataRows + 1}\n aria-colcount={dataCols}\n tabIndex={0}\n onScroll={(event) =>\n setScroll({ top: event.currentTarget.scrollTop, left: event.currentTarget.scrollLeft })\n }\n onKeyDown={onKeyDown}\n className={cn(\n \"relative h-full overflow-auto bg-background text-[13px] outline-none select-none [overscroll-behavior:contain]\",\n className,\n )}\n >\n <div role=\"rowgroup\" style={{ width: gutterWidth + totalWidth }}>\n {/* A / B / C. Sticky on both axes, so the corner stays put. */}\n <div\n className=\"sticky top-0 z-40 flex\"\n style={{ ...rowStyle, height: HEAD_HEIGHT }}\n role=\"row\"\n >\n <div\n className=\"sticky left-0 z-10 shrink-0 border-r border-b border-border bg-muted\"\n style={{ width: gutterWidth, height: HEAD_HEIGHT }}\n />\n <div className=\"shrink-0 border-b border-border bg-muted\" style={{ width: leadWidth }} />\n {visibleCols.map((col) => (\n <div\n key={col}\n role={col < dataCols ? \"columnheader\" : \"presentation\"}\n aria-colindex={col < dataCols ? col + 1 : undefined}\n onMouseDown={col < dataCols ? () => select(selected.row, col) : undefined}\n className={cn(\n \"flex shrink-0 items-center justify-center border-r border-b border-border bg-muted text-[11px] text-muted-foreground\",\n selected.col === col && col < dataCols && \"bg-accent font-medium text-foreground\",\n )}\n style={{ width: widths[col], height: HEAD_HEIGHT }}\n >\n {columnLabel(col)}\n </div>\n ))}\n <div className=\"shrink-0 border-b border-border bg-muted\" style={{ width: tailWidth }} />\n </div>\n\n {/* The file's row 1. Frozen under the letters, because a data file's\n first row is its header and reading row 40,000 without it is\n guesswork — the first thing anyone does to a sheet by hand. */}\n {/* Opaque: body rows scroll underneath this one. */}\n <div\n className=\"sticky z-30 flex bg-background\"\n style={{ ...rowStyle, top: HEAD_HEIGHT }}\n role=\"row\"\n >\n <RowHeader\n label=\"1\"\n width={gutterWidth}\n active={selected.row === 0}\n onSelect={() => select(0, selected.col)}\n />\n <div className=\"shrink-0 border-b border-foreground/25\" style={{ width: leadWidth }} />\n {visibleCols.map((col) => (\n <Cell\n key={col}\n width={widths[col]!}\n // A header label is text, and a spreadsheet aligns a cell by what\n // is in it — so it reads left even over a column of numbers.\n format=\"text\"\n text={sheet.columns[col]?.label ?? \"\"}\n header\n selected={selected.row === 0 && selected.col === col}\n onSelect={col < dataCols ? () => select(0, col) : undefined}\n colIndex={col < dataCols ? col : undefined}\n />\n ))}\n <div className=\"shrink-0 border-b border-foreground/25\" style={{ width: tailWidth }} />\n </div>\n\n {/* `presentation` so the rows below stay owned by the rowgroup above. */}\n <div role=\"presentation\" className=\"relative\" style={{ height: rowCount * ROW_HEIGHT }}>\n {Array.from({ length: Math.max(0, lastRow - firstRow) }, (_, offset) => {\n const row = firstRow + offset\n const cells = sheet.rows[row]\n return (\n <div\n key={row}\n role=\"row\"\n aria-rowindex={row < dataRows ? row + 2 : undefined}\n className=\"absolute flex\"\n style={{ ...rowStyle, top: row * ROW_HEIGHT }}\n >\n <RowHeader\n label={String(row + 2)}\n width={gutterWidth}\n active={selected.row === row + 1}\n onSelect={row < dataRows ? () => select(row + 1, selected.col) : undefined}\n />\n <div className=\"shrink-0\" style={{ width: leadWidth }} />\n {visibleCols.map((col) => {\n const column = sheet.columns[col]\n return (\n <Cell\n key={col}\n width={widths[col]!}\n format={column?.format ?? \"text\"}\n text={column ? formatCell(cells?.[col], column.format) : \"\"}\n selected={selected.row === row + 1 && selected.col === col}\n onSelect={\n row < dataRows && col < dataCols ? () => select(row + 1, col) : undefined\n }\n colIndex={col < dataCols ? col : undefined}\n />\n )\n })}\n <div className=\"shrink-0\" style={{ width: tailWidth }} />\n </div>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\nSheetGrid.displayName = \"SheetGrid\"\n\nfunction RowHeader({\n label,\n width,\n active,\n onSelect,\n}: {\n label: string\n width: number\n active: boolean\n onSelect?: () => void\n}) {\n return (\n <div\n role={onSelect ? \"rowheader\" : \"presentation\"}\n onMouseDown={onSelect}\n className={cn(\n // Above a selected cell (`z-10`): scrolling a selected column under the\n // gutter must not paint its outline over the row number.\n \"sticky left-0 z-20 flex h-full shrink-0 items-center justify-center border-r border-b border-border bg-muted text-[11px] text-muted-foreground\",\n active && \"bg-accent font-medium text-foreground\",\n )}\n style={{ width }}\n >\n {label}\n </div>\n )\n}\n\nfunction Cell({\n width,\n format,\n text,\n header,\n selected,\n onSelect,\n colIndex,\n}: {\n width: number\n format: CellFormat\n text: string\n header?: boolean\n selected: boolean\n onSelect?: () => void\n colIndex?: number\n}) {\n return (\n <div\n role={onSelect ? \"gridcell\" : \"presentation\"}\n aria-colindex={colIndex === undefined ? undefined : colIndex + 1}\n aria-selected={onSelect ? selected : undefined}\n onMouseDown={onSelect}\n // Columns are sized to their content but capped, so a long value still\n // gets clipped — the title is how the rest of it stays reachable\n // without a formula bar.\n title={text || undefined}\n className={cn(\n \"flex h-full shrink-0 items-center border-r border-b border-border px-1.5\",\n header && \"border-b-foreground/25 font-medium\",\n // Numbers and dates read right-aligned, as they do in a spreadsheet.\n format === \"text\" ? \"justify-start\" : \"justify-end tabular-nums\",\n selected && onSelect && \"relative z-10 outline-2 -outline-offset-2 outline-primary\",\n )}\n style={{ width }}\n >\n <span className=\"truncate\">{text}</span>\n </div>\n )\n}\n","/**\n * One sheet, framed the way a spreadsheet application frames one: the grid\n * fills the window, and a status bar sits under it with the sheet tabs on the\n * left and the shape of the sheet on the right.\n *\n * The frame is what makes the grid usable — a grid needs a definite height to\n * scroll inside, and a Vantage page has no guaranteed one (layouts belong to\n * the app). So it measures the space left below itself in the viewport rather\n * than asking the app to arrange for a height.\n */\nimport { useLayoutEffect, useRef, useState, type RefObject } from \"react\"\n\nimport { cn } from \"../ui/cn\"\nimport { SheetGrid } from \"./sheet-grid\"\nimport type { TableSheet } from \"./types\"\n\n/** Never collapse below this, however little viewport is left. */\nconst MIN_HEIGHT = 320\n/** Breathing room under the frame when the layout leaves none of its own. */\nconst MIN_BOTTOM_GAP = 8\n\nexport interface TableViewerProps {\n /** The sheet to render. */\n sheet: TableSheet\n /** Every sheet's name. Given more than one, a tab strip is rendered. */\n sheetNames?: string[]\n activeSheet?: number\n onSheetChange?: (index: number) => void\n /**\n * Fixed height for the frame. Without it the viewer fills the rest of the\n * viewport, which is right for a file page and wrong for a table embedded in\n * a dashboard among other cards.\n */\n height?: number | string\n className?: string\n}\n\n/**\n * What the layout keeps under the frame: every ancestor's bottom padding,\n * border and margin. It has to come out of the height, or the page ends up\n * scrollable by exactly that much (a page shell nested in a layout shell means\n * two lots of padding). Read from the box model rather than from the document\n * height, which a `min-h-screen` layout pins to the viewport and would make\n * this feed back on its own result.\n */\nfunction spaceBelow(element: HTMLElement): number {\n let total = 0\n for (let node = element.parentElement; node && node !== document.body; node = node.parentElement) {\n const style = getComputedStyle(node)\n total +=\n parseFloat(style.paddingBottom) + parseFloat(style.borderBottomWidth) + parseFloat(style.marginBottom)\n }\n return Number.isFinite(total) ? total : 0\n}\n\n/**\n * Fill the rest of the viewport. Measured rather than expressed in CSS: the\n * frame's distance from the top of the window depends on whatever the app's\n * layout put above it, which no `calc()` here can know.\n */\nfunction useFillHeight(ref: RefObject<HTMLElement | null>, enabled: boolean): number {\n const [height, setHeight] = useState(MIN_HEIGHT)\n\n useLayoutEffect(() => {\n const element = ref.current\n if (!element || !enabled) return\n const measure = () => {\n // Document-relative, not viewport-relative: `rect.top` alone shrinks as\n // the page scrolls, so a measurement taken while scrolled (a mobile URL\n // bar collapsing fires `resize`) would make the frame taller than the\n // viewport and add page scroll that never goes away.\n const rect = element.getBoundingClientRect()\n const top = rect.top + window.scrollY\n const next = Math.max(\n MIN_HEIGHT,\n window.innerHeight - top - Math.max(spaceBelow(element), MIN_BOTTOM_GAP),\n )\n // Only a real change: the frame's own height feeds back into the\n // document height, and rounding noise would loop.\n setHeight((current) => (Math.abs(current - next) > 1 ? next : current))\n }\n measure()\n const observer = new ResizeObserver(measure)\n observer.observe(document.body)\n window.addEventListener(\"resize\", measure)\n return () => {\n observer.disconnect()\n window.removeEventListener(\"resize\", measure)\n }\n }, [enabled, ref])\n\n return height\n}\n\nfunction plural(count: number, noun: string): string {\n return `${count.toLocaleString()} ${noun}${count === 1 ? \"\" : \"s\"}`\n}\n\n/** Render one parsed sheet. Exported so an app can drive it with its own data. */\nexport function TableViewer({\n sheet,\n sheetNames,\n activeSheet = 0,\n onSheetChange,\n height,\n className,\n}: TableViewerProps) {\n const frameRef = useRef<HTMLDivElement>(null)\n const filled = useFillHeight(frameRef, height === undefined)\n const tabs = sheetNames && sheetNames.length > 1 ? sheetNames : null\n\n return (\n <div\n ref={frameRef}\n className={cn(\n \"flex flex-col overflow-hidden rounded-md border border-border bg-background\",\n className,\n )}\n style={{ height: height ?? filled }}\n >\n <div className=\"min-h-0 flex-1\">\n <SheetGrid sheet={sheet} />\n </div>\n\n {/* The status bar: sheet tabs and the shape of the sheet, where a\n spreadsheet puts them. */}\n <div className=\"flex items-center gap-4 border-t border-border bg-muted/60 px-2 py-1\">\n {tabs ? (\n <div className=\"flex min-w-0 items-end gap-px overflow-x-auto\" role=\"tablist\">\n {tabs.map((name, index) => (\n <button\n key={name}\n type=\"button\"\n role=\"tab\"\n aria-selected={index === activeSheet}\n onClick={() => onSheetChange?.(index)}\n className={cn(\n \"shrink-0 rounded-t-sm border-t-2 px-3 py-1 text-xs whitespace-nowrap\",\n index === activeSheet\n ? \"border-primary bg-background font-medium text-foreground\"\n : \"border-transparent text-muted-foreground hover:text-foreground\",\n )}\n >\n {name}\n </button>\n ))}\n </div>\n ) : null}\n\n <div className=\"ml-auto flex shrink-0 items-center gap-3 text-[11px] text-muted-foreground\">\n {sheet.truncated ? (\n <span className=\"font-medium text-foreground\">\n First {sheet.rows.length.toLocaleString()} of {sheet.totalRows.toLocaleString()} rows —\n download the file for the rest\n </span>\n ) : null}\n <span>\n {plural(sheet.totalRows, \"row\")} × {plural(sheet.columns.length, \"column\")}\n </span>\n </div>\n </div>\n </div>\n )\n}\nTableViewer.displayName = \"TableViewer\"\n","/**\n * The page a `.csv` or `.xlsx` under `src/` becomes. Generated wrappers in\n * `.vantage/file-pages/` mount this; apps can mount it themselves to take over\n * the title or to render a file kept out of routing with an `_` prefix.\n */\nimport { useState } from \"react\"\nimport { DownloadIcon } from \"lucide-react\"\nimport {\n PageShell,\n PageShellActions,\n PageShellContent,\n PageShellHeader,\n PageShellHeading,\n PageShellMeta,\n PageShellTitle,\n} from \"../components\"\nimport { useQuery } from \"../query\"\nimport { Button } from \"../ui/button\"\nimport { Loading, ErrorState } from \"../ui/states\"\nimport { loadWorkbook } from \"./parse\"\nimport { TableViewer } from \"./table-viewer\"\n\nexport interface FilePageViewProps {\n /** Extension without the dot, e.g. `\"xlsx\"`. */\n kind: string\n /** URL of the file, produced by Vite's asset pipeline. */\n src: string\n /** Original file name, used for the heading fallback and the download. */\n fileName: string\n /** Title derived from the file name at generate time. */\n title?: string\n}\n\nexport function FilePageView({ kind, src, fileName, title }: FilePageViewProps) {\n const [active, setActive] = useState(0)\n\n // The framework's QueryClient is already above this in the tree, so the\n // parsed workbook is cached across navigations for free and the retry and\n // networkMode policies are the managed ones — no second provider.\n const workbook = useQuery({\n queryKey: [\"vantage:file-page\", src],\n queryFn: () => loadWorkbook(src, kind),\n staleTime: Infinity,\n })\n\n const download = (\n // `nativeButton={false}` because this renders an `<a>`: Base UI needs to\n // know it is not driving a real button, or it warns and keeps button\n // semantics that would fight the link's.\n <Button\n variant=\"outline\"\n size=\"sm\"\n nativeButton={false}\n render={<a href={src} download={fileName} />}\n >\n <DownloadIcon aria-hidden=\"true\" />\n Download\n </Button>\n )\n\n const sheets = workbook.data?.sheets ?? []\n const sheet = sheets[Math.min(active, Math.max(sheets.length - 1, 0))]\n\n return (\n <PageShell>\n {/* A slim band: the grid below wants the vertical room, and a data file\n has no description to carry. */}\n <PageShellHeader className=\"py-6\">\n <PageShellHeading>\n <PageShellTitle>{title ?? fileName}</PageShellTitle>\n <PageShellMeta>{fileName}</PageShellMeta>\n </PageShellHeading>\n <PageShellActions>{download}</PageShellActions>\n </PageShellHeader>\n\n <PageShellContent>\n {workbook.isPending ? <Loading label={`Reading ${fileName}…`} /> : null}\n\n {/* Every failure path lands here, inside the page. A data file the\n browser cannot read must not take the rest of the app down. */}\n {workbook.isError ? (\n <ErrorState\n title={`Could not display ${fileName}`}\n message={(workbook.error as Error).message}\n action={download}\n />\n ) : null}\n\n {sheet ? (\n <TableViewer\n sheet={sheet}\n sheetNames={sheets.map((s) => s.name)}\n activeSheet={active}\n onSheetChange={setActive}\n />\n ) : null}\n </PageShellContent>\n </PageShell>\n )\n}\nFilePageView.displayName = \"FilePageView\"\n"]}
|