fix(import): preserve XLSX numeric and cached text values

Keep small and high-precision numbers intact in table placement and data merge. Honor cached formula strings as text, including leading zeros and whitespace.

Co-Authored-By: OpenAI Codex <noreply@openai.com>
This commit is contained in:
storybored379
2026-10-12 18:29:37 -07:00
co-authored by OpenAI Codex
parent 91263c912f
commit d27eff31cd
3 changed files with 40 additions and 4 deletions
+3 -1
View File
@@ -2,7 +2,7 @@
**Stage: pre-alpha** · next: alpha, ~0% and ~15–25 h away; beta ~28 points and ~420–750 h beyond that (the core-workflow gate, not the percentage: ready for real work is already ~47%)
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (cancelable macOS Dock Quit) · **Target:** Adobe InDesign 2026
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (XLSX cached cell values retain numeric precision and text) · **Target:** Adobe InDesign 2026
DesignCraft aims at full Adobe InDesign parity, and to be better: faster, open (documented JSON
format + IDML), scriptable by agents (MCP), and available on the web.
@@ -129,6 +129,8 @@ list) · [roadmap.md](docs/roadmap.md) (milestones, plan) · [parity-checklist.m
Newest first.
- **2026-10-12** · Placed Excel tables and Excel data-merge records keep numeric precision, including small values, and preserve numeric-looking cached formula strings as text. No readiness percentage change.
- **2026-10-12** · macOS Dock Quit uses the same unsaved-document prompts as window and menu Quit. Repeated requests keep the current answers; Cancel retains every tab and unsaved recovery checkpoint, and completed Save/Don't Save answers exit through the ordinary event loop. No readiness percentage change.
- **2026-10-12** · Orderly native exit writes the latest recovery state after finalizing current quit approvals; incomplete or stale plans keep their documents, and Undo to the saved state clears stale recovery. Unavailable or failed recovery is reported. Cancelable macOS Dock Quit remains open (#544). No readiness percentage change.
- **2026-10-12** · Recovered documents keep a checkpoint until saved, closed or reverted, including a second crash before autosave. Restarted document IDs and explicit recovery folders preserve other snapshots; failed republishing retains the original. No readiness percentage change.
+34 -1
View File
@@ -40,6 +40,8 @@ fn value(c: &El, shared: &[String]) -> String {
match c.attr("t") {
Some("s") => v().trim().parse::<usize>().ok().and_then(|i| shared.get(i).cloned()).unwrap_or_default(),
Some("inlineStr") => c.child("is").map(El::text).unwrap_or_default(),
// A cached formula string is text even when it looks like a number.
Some("str") => v(),
Some("b") => {
if v().trim() == "1" {
"TRUE".into()
@@ -52,7 +54,7 @@ fn value(c: &El, shared: &[String]) -> String {
// Whole numbers without the trailing ".0" Excel never shows.
match raw.trim().parse::<f64>() {
Ok(f) if f.fract() == 0.0 && f.abs() < 1e15 => format!("{}", f as i64),
Ok(f) => format!("{}", (f * 1e10).round() / 1e10),
Ok(f) => f.to_string(),
Err(_) => raw,
}
}
@@ -334,4 +336,35 @@ mod tests {
assert_eq!(rows[3][1], "1");
assert!(records(&book, Some("Missing")).is_err());
}
fn one_value(cell: &str) -> Vec<u8> {
workbook_with(&format!(
r#"<worksheet><sheetData><row r="1"><c r="A1" t="inlineStr"><is><t>Value</t></is></c></row><row r="2">{cell}</row></sheetData></worksheet>"#
))
}
#[test]
fn numeric_values_keep_their_precision_in_tables_and_records() {
for text in ["1e-12", "-0.0000000000123", "1.23456789012345", "1e300", "12.0"] {
let book = one_value(&format!(r#"<c r="A2"><v>{text}</v></c>"#));
let placed = crate::import("values.xlsx", &book).unwrap();
let table = placed.story.tables.values().next().unwrap();
let rows = crate::xlsx_records(&book, None).unwrap();
for got in [&table.cell(1, 0).unwrap().text.text, &rows[1][0]] {
assert_eq!(got.parse::<f64>().unwrap(), text.parse::<f64>().unwrap(), "cell {text} became {got}");
}
}
}
#[test]
fn cached_string_values_are_not_reformatted_as_numbers() {
for text in ["00123", "1e3", "12.0", " 42 "] {
let book = one_value(&format!(r#"<c r="A2" t="str"><f>"{text}"</f><v>{text}</v></c>"#));
let placed = crate::import("values.xlsx", &book).unwrap();
let table = placed.story.tables.values().next().unwrap();
let rows = crate::xlsx_records(&book, None).unwrap();
assert_eq!(table.cell(1, 0).unwrap().text.text, text);
assert_eq!(rows[1][0], text);
}
}
}
+3 -2
View File
@@ -1,6 +1,6 @@
# File format parity
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (shared print spooler; Windows CI passes) · **Target:** Adobe InDesign 2026 (21.6)
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (XLSX cached values preserve numeric precision and text; shared print spooler; Windows CI passes) · **Target:** Adobe InDesign 2026 (21.6)
Every format InDesign 2026 reads or writes, with DesignCraft's support, fidelity and tests. The
InDesign list comes from its bundle's `Info.plist` (`CFBundleDocumentTypes`,
@@ -62,7 +62,7 @@ score below).
| HEIC | `.heic` | ✓ | ✗ | | <1% |
| Word | `.docx` | ✓ styles, footnotes, tables, track changes, options | ✓ styles by name, footnotes, tables, tabs, breaks, moved text (#257), style mapping and conflicts | `.doc` not supported (InDesign reads it) | 2% |
| RTF | `.rtf` | ✓ | ✓ | | <1% |
| Excel | `.xlsx`, `.xls` | ✓ | ~ `.xlsx` first sheet's used range | no sheet/range options; `.xls` ✗ | <1% |
| Excel | `.xlsx`, `.xls` | ✓ | ~ `.xlsx` first sheet's used range | cached numbers keep their precision and formula strings stay text; no sheet/range options; `.xls` ✗ | <1% |
| Plain text, Markdown | `.txt`, `.md` | ✓ (txt) | ✓ | | <1% |
| InDesign Tagged Text | `.txt` | ✓ | ✓ import and export | | <1% |
| CSV / TSV (Data Merge) | | ✓ | ✓ (+ Excel) | | <1% |
@@ -107,4 +107,5 @@ for real work** (estimated). INDD alone moves this dimension by up to 30 points.
| Date | Change | Summary |
|---|---|---|
| 2026-10-12 | minor | XLSX table placement and data merge preserve small numeric values and cached formula strings; synthetic regressions in `textimport::xlsx::tests`. Scores unchanged. |
| 2026-10-10 | major | Created from InDesign 2026's declared document types and filters, `plan/indesign/08-file-formats.md` and the code |