@particle-academy/holy-sheet 2.10.2 → 2.11.0

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,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
10
10
 
11
11
  ## [Unreleased]
12
12
 
13
+ ## [2.11.0] - 2026-10-27
14
+
15
+ ### Added
16
+
17
+ - **Excel `.xltx` templates read, and `.ots` templates marked.** `read()` /
18
+ `describe()` read an `.xltx` exactly as its `.xlsx` twin and add
19
+ `sourceKind: "template"`; an `.ots` (already read, unmarked) now says so too.
20
+ `Workbook` gains a trailing optional `sourceKind` (default `"document"`).
21
+ Document reads are unchanged and carry no `sourceKind` key, so nothing to do
22
+ unless you want to tell the two apart. Mirrors PHP holy-sheet.
23
+ - **`Agent.convertTemplate(bytes, to?)`** (also on `HolySheet`) and the new
24
+ `holy-sheet` bin, `npx holy-sheet template:convert <in> <out>
25
+ [--to=document|template] [--force]`, turn a template into its workbook twin
26
+ and back. Only the declaration is rewritten: the workbook part's content-type
27
+ value (OOXML), or the `mimetype` entry plus the manifest root's `media-type`
28
+ (ODF 1.3 Part 2 section 3.3 requires them to agree). Every other zip member is
29
+ copied as its original record, byte for byte; `mimetype` stays first and
30
+ stored. The bin is Node-only and never imported by the isomorphic index.
31
+ - `OfficeTemplateRefused` with a constant `reason`.
32
+
33
+ ### Changed
34
+
35
+ - **A macro-enabled template (`.xltm`) is now refused** with
36
+ `OfficeTemplateRefused("macro_enabled")`; it used to be read as a workbook with
37
+ its VBA silently ignored. So is an `.xltx` carrying a `vbaProject.bin`. An
38
+ `.xlsm` still reads as before but is never converted.
39
+ - A package that declares a template of another family is refused with
40
+ `family_mismatch` instead of being read as whatever its parts looked like.
41
+
13
42
  ## [2.10.2] - 2026-10-26
14
43
 
15
44
  ### 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