@particle-academy/holy-sheet 2.10.2 → 2.11.1

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/CHANGELOG.md CHANGED
@@ -10,6 +10,55 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
10
10
 
11
11
  ## [Unreleased]
12
12
 
13
+ ## [2.11.1] - 2026-10-27
14
+
15
+ ### Fixed
16
+
17
+ - **An explicit `{value: <string>}` cell is now written as a string, exactly
18
+ as given**, matching PHP holy-sheet and holy-sheet-py. Numeric-string
19
+ coercion used to run on the object form too, so `{value: "+1"}` was written
20
+ as the number 1, `{value: "007"}` as 7 and `{value: "1e5"}` as 100000: a
21
+ phone prefix, zip code or part number lost its characters with no error.
22
+ This applies in `rows` and in the sparse `cells` map, under any column type
23
+ or number format, and to a `set_cell` op's `value`. Unchanged: a BARE string
24
+ in a row or a `cells` entry is still coerced (`"+1"` is still 1) and a bare
25
+ `"=..."` is still a formula; an object value that is already a number is
26
+ still a number; and a string under a `date` / `datetime` display format is
27
+ still converted to a date serial. `read()` returns such a cell as the same
28
+ string.
29
+ **What a consumer must do:** if you relied on `{value: "100"}` becoming a
30
+ number, pass the number (`{value: 100}`) or the bare string (`"100"`).
31
+ Otherwise nothing.
32
+
33
+ ## [2.11.0] - 2026-10-27
34
+
35
+ ### Added
36
+
37
+ - **Excel `.xltx` templates read, and `.ots` templates marked.** `read()` /
38
+ `describe()` read an `.xltx` exactly as its `.xlsx` twin and add
39
+ `sourceKind: "template"`; an `.ots` (already read, unmarked) now says so too.
40
+ `Workbook` gains a trailing optional `sourceKind` (default `"document"`).
41
+ Document reads are unchanged and carry no `sourceKind` key, so nothing to do
42
+ unless you want to tell the two apart. Mirrors PHP holy-sheet.
43
+ - **`Agent.convertTemplate(bytes, to?)`** (also on `HolySheet`) and the new
44
+ `holy-sheet` bin, `npx holy-sheet template:convert <in> <out>
45
+ [--to=document|template] [--force]`, turn a template into its workbook twin
46
+ and back. Only the declaration is rewritten: the workbook part's content-type
47
+ value (OOXML), or the `mimetype` entry plus the manifest root's `media-type`
48
+ (ODF 1.3 Part 2 section 3.3 requires them to agree). Every other zip member is
49
+ copied as its original record, byte for byte; `mimetype` stays first and
50
+ stored. The bin is Node-only and never imported by the isomorphic index.
51
+ - `OfficeTemplateRefused` with a constant `reason`.
52
+
53
+ ### Changed
54
+
55
+ - **A macro-enabled template (`.xltm`) is now refused** with
56
+ `OfficeTemplateRefused("macro_enabled")`; it used to be read as a workbook with
57
+ its VBA silently ignored. So is an `.xltx` carrying a `vbaProject.bin`. An
58
+ `.xlsm` still reads as before but is never converted.
59
+ - A package that declares a template of another family is refused with
60
+ `family_mismatch` instead of being read as whatever its parts looked like.
61
+
13
62
  ## [2.10.2] - 2026-10-26
14
63
 
15
64
  ### Security
package/README.md CHANGED
@@ -76,6 +76,33 @@ when there is one). What maps and what does not is listed in the PHP package's
76
76
  [`docs/ReadPath.md`](https://github.com/Particle-Academy/holy-sheet/blob/main/docs/ReadPath.md#opendocument-spreadsheets-ods);
77
77
  this port reads the same fixtures and is diffed against it.
78
78
 
79
+ ### Excel and LibreOffice templates (.xltx, .ots)
80
+
81
+ An `.xltx` is an `.xlsx` whose workbook part is declared a template; an `.ots`
82
+ is an `.ods` whose `mimetype` (and manifest root entry) says
83
+ `spreadsheet-template`. `read()` / `describe()` read both exactly as their twins
84
+ and add `sourceKind: "template"` (also `Workbook#sourceKind` from
85
+ `readWorkbook()`). A document read has no `sourceKind` key, as before.
86
+
87
+ ```ts
88
+ Agent.read(xltxBytes); // { ..., sourceKind: "template" }
89
+ Agent.convertTemplate(xltxBytes); // .xlsx bytes ("document" | "template" | null = flip)
90
+ ```
91
+
92
+ ```
93
+ npx holy-sheet template:convert budget.xltx budget.xlsx
94
+ npx holy-sheet template:convert budget.ods budget.ots --to=template
95
+ ```
96
+
97
+ Conversion rewrites only the declaration: the content-type value in
98
+ `[Content_Types].xml`, or the ODF `mimetype` entry plus the manifest's root
99
+ `media-type` (ODF 1.3 requires the two to match). Every other member is copied
100
+ as its original zip record, byte for byte; `mimetype` stays first and stored.
101
+ Refused with `OfficeTemplateRefused` (a constant `reason`): macro-enabled `.xltm`
102
+ (`macro_enabled`; an `.xlsm` is never converted either) and a package declaring
103
+ a template of another family (`family_mismatch`). The archive guards apply
104
+ first. Mirrors PHP `Agent::convertTemplate()`.
105
+
79
106
  ### Versions as diffs
80
107
 
81
108
  `Agent.diff(a, b)` returns the ops that turn one schema into another, and