fix: decode .sqlplan files the way SSMS writes them; name the parse failure
- lib/plan-file.ts: BOM-aware decode for UTF-8, UTF-16LE/BE (with and without BOM) and UTF-32, with a NUL-density fallback for BOM-less UTF-16. The browser had a two-byte FF FE sniff only, so a UTF-16BE or BOM-less plan arrived as NUL-filled junk and the digest blamed the export. - digestPlan now quotes fast-xml-parser's first line instead of a fixed sentence, so a truncated file, a stray entity and a wrong file stay distinguishable. - plan-file.ts holds the decode so the XML parser stays out of the client bundle. - tests: 6 encodings round-trip through decodePlan into a digest; a truncated plan's message is asserted to carry a reason; e2e drops a real UTF-16LE file. 36 unit, 23 e2e. - history.spec picked the rail's first row, which is now one of the new failing-input rows; it selects the newest finished run instead. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
3d1866367b
commit
4b5c19b5d2
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
import { useState } from "react";
|
||||
import { readSse } from "@/lib/stream";
|
||||
import { decodePlan } from "@/lib/plan-file.ts";
|
||||
import { ReportView } from "./report-view";
|
||||
import { ExportButtons } from "./export-buttons";
|
||||
|
||||
@@ -59,10 +60,8 @@ export function Runner() {
|
||||
<input type="file" accept=".sqlplan,.xml" aria-label="Load a .sqlplan file" style={{ fontSize: "var(--qai-text-xs)" }}
|
||||
onChange={async (e) => {
|
||||
const f = e.target.files?.[0]; if (!f) return;
|
||||
const buf = new Uint8Array(await f.arrayBuffer());
|
||||
// SSMS saves UTF-16LE; File.text() decodes that as UTF-8 and fills the plan with NUL bytes.
|
||||
const utf16 = buf[0] === 0xff && buf[1] === 0xfe;
|
||||
setXml(new TextDecoder(utf16 ? "utf-16le" : "utf-8").decode(buf).replace(/^/, ""));
|
||||
// SSMS saves UTF-16LE; File.text() would decode that as UTF-8 and fill the plan with NULs.
|
||||
setXml(decodePlan(new Uint8Array(await f.arrayBuffer())));
|
||||
}} />
|
||||
{at >= 0 && <span className="pill" aria-live="polite">{at + 1} of 4 · {LABEL[STAGES[at]]}</span>}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user