Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
150 commits
Select commit Hold shift + click to select a range
e773217
feat(office): add canonical XLSX workbook selectors
bobzhang Jul 16, 2026
f60e9eb
refactor(office): share bounded output accounting
bobzhang Jul 16, 2026
cd4e0be
feat(office): add bounded XLSX read projection
bobzhang Jul 16, 2026
e5e6bd2
feat(office): add bounded XLSX read outputs
bobzhang Jul 16, 2026
807d00f
feat(office): dispatch bounded structured reads to xlsx
bobzhang Jul 16, 2026
ac6802f
test(office): cover public xlsx read contract
bobzhang Jul 16, 2026
1dec18c
test(office): keep byte projection helper test-only
bobzhang Jul 16, 2026
f056d4c
refactor(office): retire duplicate docx zip limits
bobzhang Jul 16, 2026
bbfb430
style(office): format capability snapshots
bobzhang Jul 16, 2026
0bcb534
fix(office): close xlsx read review gaps
bobzhang Jul 16, 2026
23db2bf
fix(office): harden xlsx read projections
bobzhang Jul 16, 2026
66cab47
fix(office): close final xlsx read review gaps
bobzhang Jul 17, 2026
a5c8153
fix(office): harden xlsx structured reads
bobzhang Jul 17, 2026
105cbd1
fix(xlsx): translate shared formulas and relocated parts
bobzhang Jul 17, 2026
8329a5a
fix(xlsx): preserve 3-D formulas and default main parts
bobzhang Jul 17, 2026
7c7f0a1
chore: migrate executable package manifests
bobzhang Jul 17, 2026
acc8234
fix(xlsx): bound semantic read work
bobzhang Jul 17, 2026
03852d5
fix(ooxml): resolve namespace-qualified package XML
bobzhang Jul 17, 2026
4379012
fix(xlsx): reject malformed shared formulas
bobzhang Jul 17, 2026
ea0d7d7
fix(ooxml): harden package metadata parsing
bobzhang Jul 17, 2026
5560a02
fix(xlsx): canonicalize namespace-qualified parts
bobzhang Jul 17, 2026
8a58a08
fix(xlsx): budget sqref normalization work
bobzhang Jul 17, 2026
e7279ba
test(xlsx): align discovery fixtures with root relationships
bobzhang Jul 17, 2026
e74b771
fix(xlsx): propagate cancellation through reads
bobzhang Jul 17, 2026
6d42fdc
fix(xlsx): validate shared formula groups
bobzhang Jul 17, 2026
6abb5a6
fix(office): publish exact format capabilities
bobzhang Jul 17, 2026
75a4071
fix(office): detect bounded input size races
bobzhang Jul 17, 2026
3f4bb81
chore(ooxml): remove redundant view conversion
bobzhang Jul 17, 2026
9db55f6
fix: harden XLSX XML and relationship parsing
bobzhang Jul 17, 2026
2c634c8
fix: honor cancellation throughout XLSX output
bobzhang Jul 17, 2026
3a97af7
docs: refresh OOXML relationship interface
bobzhang Jul 17, 2026
c3b5d3a
ci: normalize XLSX smoke fixture
bobzhang Jul 17, 2026
6ac6fcf
fix: isolate XLSX core XML from extensions
bobzhang Jul 17, 2026
c44cdb0
fix: bound XLSX read cancellation latency
bobzhang Jul 17, 2026
e0e3741
fix: accept case-insensitive XLSX media types
bobzhang Jul 17, 2026
fb382eb
fix: preserve XLSX query literal whitespace
bobzhang Jul 17, 2026
284bf7f
fix: bind XLSX payloads to their cells
bobzhang Jul 18, 2026
e229e5e
fix: cancel XLSX CRC verification promptly
bobzhang Jul 18, 2026
0c16c5c
fix: cancel XLSX XML passes promptly
bobzhang Jul 18, 2026
32628a7
fix: unify OPC part-name identity
bobzhang Jul 18, 2026
66fbe40
chore: refresh package interfaces
bobzhang Jul 18, 2026
9ff8472
fix: resolve OPC physical part names safely
bobzhang Jul 18, 2026
8fa1330
fix: harden XLSX XML core parsing
bobzhang Jul 18, 2026
cf40d67
fix: bound Office format preflight
bobzhang Jul 18, 2026
e016c2a
fix: account for XLSX post-parse work
bobzhang Jul 18, 2026
bbc67c8
fix: yield during bounded XLSX scans
bobzhang Jul 18, 2026
ca5f5ad
test: refresh bounded Office read error
bobzhang Jul 18, 2026
f727a66
fix(ooxml): reject malformed processing markup
bobzhang Jul 18, 2026
061f73b
fix(xlsx): close read correctness gaps
bobzhang Jul 18, 2026
e5b9ee9
perf(xlsx): build bounded cell indexes during read
bobzhang Jul 18, 2026
244821a
fix(office): bound cooperative XLSX output
bobzhang Jul 18, 2026
1e816c7
chore: refresh generated interfaces
bobzhang Jul 18, 2026
9b2e5b6
fix(read): close parser and query review gaps
bobzhang Jul 18, 2026
279d84f
fix(office): make DOCX reads cooperative
bobzhang Jul 18, 2026
1962267
fix(xlsx): honor 1904 dates in formula calculation
bobzhang Jul 18, 2026
d4917f7
chore: refresh generated interfaces
bobzhang Jul 18, 2026
23b25e3
fix(xlsx): terminate workday at date bounds
bobzhang Jul 18, 2026
f88a970
fix(office): bound structural diagnostics
bobzhang Jul 18, 2026
582d3cb
fix(ooxml): enforce XML name and BOM rules
bobzhang Jul 18, 2026
b5075d8
fix(xlsx): honor extension namespace identity
bobzhang Jul 18, 2026
6c8710a
fix(office): make DOCX text scans cooperative
bobzhang Jul 18, 2026
9debb3a
fix(read): poll long validation passes
bobzhang Jul 18, 2026
0b07bd0
chore: refresh generated interfaces
bobzhang Jul 18, 2026
a3d49b6
fix(xlsx): bound formatted text expansion
bobzhang Jul 18, 2026
575f563
fix(xlsx): bind feature readers to XML namespaces
bobzhang Jul 18, 2026
7442596
fix(xlsx): avoid shared-formula bulk copies
bobzhang Jul 18, 2026
4a12a5f
fix(xlsx): bound read preprocessing
bobzhang Jul 18, 2026
e485dc6
fix(docx): poll relationship validation
bobzhang Jul 18, 2026
96f8592
fix(zip): poll while initializing owned copies
bobzhang Jul 18, 2026
52f40ab
fix(xlsx): reject derivable OPC part names
bobzhang Jul 18, 2026
b9b2c51
docs(office): document compact JSON output
bobzhang Jul 18, 2026
10bbcf6
chore: refresh generated interfaces
bobzhang Jul 18, 2026
198e3d6
fix(zip): avoid hidden initialization in cancellable copies
bobzhang Jul 18, 2026
2cc0ba5
fix(xlsx): canonicalize DrawingML compatibility prefixes
bobzhang Jul 18, 2026
916bd9f
docs(office): distinguish success and failure JSON layout
bobzhang Jul 18, 2026
fd62f59
fix(office): count XLSX outline metadata without copies
bobzhang Jul 18, 2026
b54bea4
fix(xlsx): bound OPC part-name indexing
bobzhang Jul 18, 2026
6e446f9
fix(office): bound shared formula translation
bobzhang Jul 18, 2026
5e687e3
fix(xlsx): preserve shared formulas across consumers
bobzhang Jul 18, 2026
245e633
fix(xlsx): reject ambiguous package markup
bobzhang Jul 18, 2026
a7c89e9
fix(ooxml): apply MCE to relationship parts
bobzhang Jul 18, 2026
317bbf6
fix(ooxml): bound part-name trie allocation
bobzhang Jul 18, 2026
a11ed39
fix(read): avoid eager bounded-buffer copies
bobzhang Jul 18, 2026
e141ea0
test: guard JavaScript backend
bobzhang Jul 18, 2026
542c4e8
fix(xlsx): state async parse cancellation boundary
bobzhang Jul 18, 2026
9b42361
chore: upgrade async runtime to 0.20.2
bobzhang Jul 18, 2026
6342b83
fix(ooxml): bound MCE relationship state
bobzhang Jul 18, 2026
80abe03
fix(ooxml): honor MCE directive semantics
bobzhang Jul 18, 2026
82cc5b4
fix(xlsx): bound Excel date conversion
bobzhang Jul 18, 2026
0b5f4fc
fix(xlsx): resolve relationship targets strictly
bobzhang Jul 18, 2026
0d83988
fix(ooxml): reject uppercase hex references
bobzhang Jul 18, 2026
d4fb636
fix(xlsx): calculate ISO weeks across date epochs
bobzhang Jul 18, 2026
90ee0c9
test(xlsx): use strict pivot relationship targets
bobzhang Jul 18, 2026
47688c9
fix(xlsx): preserve ISO week epoch semantics
bobzhang Jul 18, 2026
148b9a8
fix(xlsx): bound fraction number formatting
bobzhang Jul 18, 2026
185ab9c
fix(ooxml): bound OPC part-name registry growth
bobzhang Jul 18, 2026
ce5030e
fix(ooxml): reject MCE namespace directives
bobzhang Jul 18, 2026
002c95a
fix(xlsx): validate root relationship targets
bobzhang Jul 18, 2026
59db854
fix(xlsx): preserve phantom ISO week
bobzhang Jul 18, 2026
af17443
fix(ooxml): enforce relationship MCE grammar
bobzhang Jul 18, 2026
96c67ee
fix(xlsx): project SpreadsheetML MCE fallbacks
bobzhang Jul 18, 2026
240d0fe
fix(xlsx): floor serials for calendar formulas
bobzhang Jul 18, 2026
83f72fa
fix(xlsx): contain TEXT formatter failures
bobzhang Jul 18, 2026
93685db
test(xlsx): align percent overflow expectations
bobzhang Jul 18, 2026
658f9f0
fix(xlsx): bound shared formula materialization
bobzhang Jul 18, 2026
db270a7
test(office): align percent overflow contract
bobzhang Jul 18, 2026
7ee43b4
fix(xlsx): scale percent formats incrementally
bobzhang Jul 18, 2026
ecd4d8a
fix(xlsx): propagate spill calculation failures
bobzhang Jul 18, 2026
44a7f16
fix(xlsx): project MCE conservatively
bobzhang Jul 18, 2026
5c88494
fix(ooxml): validate package declarations strictly
bobzhang Jul 18, 2026
495cd95
fix(xlsx): resolve relationships with bounded OPC paths
bobzhang Jul 18, 2026
59bc975
fix(xlsx): enforce relationship content identities
bobzhang Jul 18, 2026
858fa80
fix(office): aggregate XLSX used-range scans
bobzhang Jul 18, 2026
9e16ed8
fix(xlsx): validate parsed sheet names
bobzhang Jul 18, 2026
3fa46e1
fix(xlsx): make row duplication transactional
bobzhang Jul 18, 2026
07ae177
fix(xlsx): bound cooperative formatting metadata
bobzhang Jul 18, 2026
0cc7f16
fix(xlsx): make structural cancellation atomic
bobzhang Jul 18, 2026
738c98a
fix(xlsx): authenticate relationship and image parts
bobzhang Jul 18, 2026
ec12292
fix(ooxml): scope MCE processing rules correctly
bobzhang Jul 18, 2026
3cb28eb
fix(ooxml): enforce OPC lexical grammars
bobzhang Jul 18, 2026
b8ab400
fix(xlsx): clamp relationship paths at package root
bobzhang Jul 18, 2026
fc393b0
fix(xlsx): shift structural sqref ranges
bobzhang Jul 18, 2026
5a89f99
fix(xlsx): validate workbook sheet identity
bobzhang Jul 18, 2026
b2baeb6
fix(xlsx): normalize workday date serials
bobzhang Jul 18, 2026
628c665
fix(xlsx): project DrawingML compatibility branches
bobzhang Jul 18, 2026
c6c2027
fix(xlsx): validate resolved worksheet ownership
bobzhang Jul 18, 2026
7727742
fix(xlsx): hide worksheet ownership tokens
bobzhang Jul 19, 2026
adf411a
fix(xlsx): isolate drawing extension payloads
bobzhang Jul 19, 2026
bb1312a
fix(office): enforce XLSX scan ceiling upfront
bobzhang Jul 19, 2026
c68e823
fix(xlsx): seal worksheet membership
bobzhang Jul 19, 2026
32236d8
fix(office): reject XLSX scan limits before I/O
bobzhang Jul 19, 2026
260b08b
fix(xlsx): validate drawing reader paths
bobzhang Jul 19, 2026
9606879
fix(xlsx): meter DrawingML preprocessing
bobzhang Jul 19, 2026
8277ba4
test(office): use schema-valid chart anchors
bobzhang Jul 19, 2026
8874a65
fix(xlsx): seal workbook tab membership
bobzhang Jul 19, 2026
9019a62
fix(xlsx): bind sheet drawing relationships
bobzhang Jul 19, 2026
383686f
fix(xlsx): constrain DrawingML reader targets
bobzhang Jul 19, 2026
ef41358
fix(xlsx): bind chartsheets to drawing charts
bobzhang Jul 19, 2026
50510a7
fix(xlsx): accept absolute chart anchors
bobzhang Jul 19, 2026
6e0515e
fix(xlsx): isolate absolute chart anchors
bobzhang Jul 19, 2026
be63589
fix(xlsx): tolerate unsupported drawing objects
bobzhang Jul 19, 2026
5036e26
fix(xlsx): accept valid DrawingML rich text
bobzhang Jul 19, 2026
df452a3
fix(xlsx): preserve native absolute drawing geometry
bobzhang Jul 19, 2026
514d6d6
fix(xlsx): preserve drawing anchor geometry
bobzhang Jul 19, 2026
60eb761
fix(xlsx): preserve shape rich text
bobzhang Jul 19, 2026
3563202
feat(ooxml): enumerate package relationships
bobzhang Jul 19, 2026
0267847
fix(xlsx): preserve opaque drawing anchors
bobzhang Jul 19, 2026
2a3fe67
fix(xlsx): preserve numeric and style boundaries
bobzhang Jul 19, 2026
c79e2cc
fix(xlsx): preserve row style boundaries
bobzhang Jul 19, 2026
f02b093
fix(xlsx): preserve custom geometry anchors
bobzhang Jul 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 52 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ jobs:
# The nightly toolchain is required: mbtexcel depends on
# moonbitlang/async >= 0.20 (wasm filesystem support) and its xlsx CLI
# targets the wasm backend, both of which need nightly. `moon work sync`
# has aligned the workspace members on async@0.20.1 + x@0.4.43.
# has aligned the workspace members on async@0.20.2 + x@0.4.43.
- name: Set up MoonBit (nightly)
run: |
curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash -s nightly
Expand Down Expand Up @@ -163,12 +163,21 @@ jobs:
- name: Type check (wasm)
run: moon check --target wasm

# Keep the JavaScript runtime honest as well. Floating-point formatting
# and target-specific package declarations have both regressed here
# without affecting native or Wasm builds.
- name: Type check (js)
run: moon check --target js

# An unfiltered invocation traverses every moon.work member and all of
# its packages. Keep this module-wide so new portable child packages are
# covered automatically instead of silently receiving root-only tests.
- name: Test complete workspace (wasm)
run: moon test --target wasm

- name: Test complete workspace (js)
run: moon test --target js

# Run all members' native test suites in one pass. Covers mbtexcel
# (including OpenXML SDK schema validation via .NET), docx2html
# (converter/reader/fixtures/stress), and pdflite (reader/writer/
Expand Down Expand Up @@ -281,6 +290,48 @@ jobs:
and .success == false
and .error.code == "office.unknown_format"
and .error.details.suggestions == ["xlsx"]' office-wasm-error.json
# XLSX structured reads share the validated bounded archive and use
# canonical name-keyed paths even when the input selector is positional.
# The third-party Book1 fixture has intersecting shared-formula ranges;
# normalize that unrelated invalid metadata through the raw transaction
# surface before exercising the fixture's original contents.
xlsx_source=fixtures/excelize/test/Book1.xlsx
xlsx_sheet="$RUNNER_TEMP/office-book1-sheet2.xml"
xlsx_sheet_valid="$RUNNER_TEMP/office-book1-sheet2-valid.xml"
xlsx_fixture="$RUNNER_TEMP/office-Book1-valid.xlsx"
moon run --target wasm office/cmd/office -- raw read "$xlsx_source" /Sheet2 --output "$xlsx_sheet" >/dev/null
sed -e 's/ref="F11:H11"/ref="F11:F11"/' -e 's/<f t="shared" si="0"><\/f>/<f t="shared" si="1"><\/f>/' "$xlsx_sheet" >"$xlsx_sheet_valid"
moon run --target wasm office/cmd/office -- raw replace "$xlsx_source" /Sheet2 --xml-file "$xlsx_sheet_valid" --out "$xlsx_fixture" --json >/dev/null
xo=$(moon run --target wasm office/cmd/office -- outline "$xlsx_fixture" --json 2>office-wasm.err) || { echo "office XLSX outline failed; stderr:"; cat office-wasm.err; exit 1; }
echo "$xo" | jq -e '.success == true
and .data.schema == "office.xlsx.outline/1"
and .data.path == "/xlsx/workbook"
and [.data.sheets[].path] == ["/xlsx/sheet[name=\"Sheet1\"]", "/xlsx/sheet[name=\"Sheet2\"]"]'
singleton_fixture=fixtures/excelize/test/OverflowNumericCell.xlsx
xs=$(moon run --target wasm office/cmd/office -- outline "$singleton_fixture" --json 2>office-wasm.err) || { echo "office XLSX singleton outline failed; stderr:"; cat office-wasm.err; exit 1; }
echo "$xs" | jq -e '.success == true
and .data.sheets[0].used_range.reference == "A1:A1"
and .data.sheets[0].used_range.path == "/xlsx/sheet[name=\"Sheet1\"]/range[A1:A1]"'
xsg=$(moon run --target wasm office/cmd/office -- get "$singleton_fixture" '/xlsx/sheet[1]/range[A1:A1]' --json 2>office-wasm.err) || { echo "office XLSX singleton get failed; stderr:"; cat office-wasm.err; exit 1; }
echo "$xsg" | jq -e '.success == true
and .data.reference == "A1:A1"
and [.data.cells[].reference] == ["A1"]'
xg=$(moon run --target wasm office/cmd/office -- get "$xlsx_fixture" '/xlsx/sheet[1]/range[A19:B19]' --json 2>office-wasm.err) || { echo "office XLSX get failed; stderr:"; cat office-wasm.err; exit 1; }
echo "$xg" | jq -e '.success == true
and .data.schema == "office.xlsx.element/1"
and .data.path == "/xlsx/sheet[name=\"Sheet1\"]/range[A19:B19]"
and [.data.cells[].reference] == ["A19", "B19"]
and .data.cells[1].formula == "SUM(Sheet2!D2,Sheet2!D11)"'
xt=$(moon run --target wasm office/cmd/office -- text "$xlsx_fixture" --under '/xlsx/sheet[name="Sheet1"]' --offset 1 --limit 2 --json 2>office-wasm.err) || { echo "office XLSX text failed; stderr:"; cat office-wasm.err; exit 1; }
echo "$xt" | jq -e '.success == true
and .data.schema == "office.xlsx.text/1"
and .data.matched_total == 5
and [.data.entries[].text] == ["237", "Column1"]'
xq=$(moon run --target wasm office/cmd/office -- query "$xlsx_fixture" 'cell[type=formula][formula~=IF]' --under '/xlsx/sheet[name="Sheet2"]' --json 2>office-wasm.err) || { echo "office XLSX query failed; stderr:"; cat office-wasm.err; exit 1; }
echo "$xq" | jq -e '.success == true
and .data.schema == "office.xlsx.query/1"
and .data.matched_total == 4
and [.data.matches[].reference] == ["F11", "G11", "H11", "I11"]'
# DOCX structured reads share one canonical bounded projection.
# Drive every command through the wasm async filesystem path.
o=$(moon run --target wasm office/cmd/office -- outline docx2html/tests/cram/fixtures/single-paragraph.docx --json 2>office-wasm.err) || { echo "office DOCX outline failed; stderr:"; cat office-wasm.err; exit 1; }
Expand Down
14 changes: 9 additions & 5 deletions README.mbt.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,7 @@ test "validate output" {

`office/cmd/office` is the agent-oriented facade for DOCX and XLSX packages.
Its registry-driven help, format detection, validated raw OOXML fallback, and
DOCX structured reads use versioned JSON envelopes and explicit resource
limits:
structured reads use versioned JSON envelopes and explicit resource limits:

```sh
moon run office/cmd/office -- help docx
Expand All @@ -321,12 +320,17 @@ moon run office/cmd/office -- outline report.docx --json
moon run office/cmd/office -- get report.docx '/docx/body/p[1]' --json
moon run office/cmd/office -- text report.docx --under '/docx/comments/comment[id="0"]'
moon run office/cmd/office -- query report.docx --kind paragraph --text revenue --ignore-case --json
moon run office/cmd/office -- outline book.xlsx --json
moon run office/cmd/office -- get book.xlsx '/xlsx/sheet[name="Data"]/range[A1:C12]' --json
moon run office/cmd/office -- text book.xlsx --under '/xlsx/sheet[name="Data"]' --json
moon run office/cmd/office -- query book.xlsx 'cell[type=formula]' --under '/xlsx/sheet[name="Data"]' --json
```

The four DOCX read schemas are `office.docx.outline/1`,
`office.docx.element/1`, `office.docx.text/1`, and `office.docx.query/1`, all
DOCX results use the `office.docx.{outline,element,text,query}/1` family and
XLSX results use `office.xlsx.{outline,element,text,query}/1`; every result is
inside `office.output/1`. See
[Unified Office DOCX reads](docs/office-docx-read.md) and
[Unified Office DOCX reads](docs/office-docx-read.md),
[Unified Office XLSX reads](docs/office-xlsx-read.md), and
[Canonical Office selectors](docs/office-selectors.md).

## XLSX command-line tool
Expand Down
4 changes: 1 addition & 3 deletions cmd/demos/moon.pkg
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,4 @@ import {

supported_targets = "native"

options(
"is-main": true,
)
pkgtype(kind: "executable")
4 changes: 1 addition & 3 deletions cmd/main/moon.pkg
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@ import {

supported_targets = "native+js"

options(
"is-main": true,
)
pkgtype(kind: "executable")
4 changes: 1 addition & 3 deletions cmd/parity/moon.pkg
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,4 @@ import {

supported_targets = "native"

options(
"is-main": true,
)
pkgtype(kind: "executable")
6 changes: 2 additions & 4 deletions cmd/xlsx/moon.pkg
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
"moonbitlang/core/argparse",
"moonbitlang/async",
"moonbitlang/async/fs" @async/fs,
"moonbitlang/async/os_error" @os_error,
"moonbitlang/async/os_error",
"moonbitlang/core/env",
"moonbitlang/core/encoding/utf8" @encoding/utf8,
"moonbitlang/core/string",
Expand All @@ -16,6 +16,4 @@ import {

supported_targets = "native+wasm"

options(
"is-main": true,
)
pkgtype(kind: "executable")
1 change: 0 additions & 1 deletion crypto/moon.pkg
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import {
"moonbitlang/core/debug",
}

109 changes: 98 additions & 11 deletions docs/agent-json-schemas.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,16 @@ disagree, the tests are the source of truth and this document has a bug.
`images`, `pivot_tables`, `defined_names`, `cells`) are always present
(possibly `[]`); optional sub-object fields — including list-valued ones
like `fill.colors` or a style's `border` — may be omitted entirely.
- **Index bases**: sheet `index` is 0-based tab order. Rows and columns are
never sent as bare numbers; cell and range references are A1-style strings.
- Output is pretty-printed (2-space indent) UTF-8 with a trailing newline,
deterministic for a given workbook.
- **Index bases**: standalone `xlsx.*` payloads use 0-based sheet `index`
values; unified `office.xlsx.*` payloads use 1-based sheet `index` values.
Rows and columns are never sent as bare numbers; cell and range references
are A1-style strings.
- Output is deterministic UTF-8 with a trailing newline. Standalone xlsx and
docx inspection commands use a 2-space indent. Successful unified `office`
`outline`, `get`, `text`, and `query` envelopes are compact so their output
ceiling can be accounted exactly; unified `--json` failure envelopes use a
2-space indent. JSON Lines output is compact, one value per line. Consumers
must not depend on insignificant whitespace.

## `xlsx.outline/1` — workbook structure map (`xlsx outline <file>`)

Expand Down Expand Up @@ -168,10 +174,12 @@ scanning it itself. Scans the sheet's used range by default, or the
- `text=TEXT` — the string cell equals `TEXT`; `text~=TEXT` — contains it.
A blank cell (an empty stored string) never matches a `text`/`string`
predicate.
- A predicate argument (the `TEXT` after `=`/`~=`, the `N` after an operator)
is trimmed of surrounding whitespace and cannot contain `]` (which closes
the predicate). `text=`/`text~=`/`formula~=` require a non-empty value, and a
`value` bound must be a finite number (`NaN`/`Infinity` are rejected).
- A `TEXT` predicate argument is preserved exactly, including surrounding
whitespace. Balanced brackets are allowed unquoted. A value beginning with
`"` must be one complete JSON string, which represents whitespace-only text,
`]`, quotes, backslashes, or control characters without selector ambiguity.
`text=`/`text~=`/`formula~=` require a non-empty value. Numeric `value`
bounds are trimmed and must be finite (`NaN`/`Infinity` are rejected).
- `query` is read-only. A malformed selector, an oversized scan, or a missing
sheet fails with a non-zero exit and a one-line `error:` message; nothing is
written.
Expand Down Expand Up @@ -429,9 +437,10 @@ document. Success is `{schema, success: true, data, warnings?}`; failure is
`code`, bounded `message`, and optional bounded `details`. The optional warning
array contains `{code, message}` records.

The DOCX read commands below share canonical `office.selector/1` paths and one
bounded projection. Full command, selector, limit, and error-code details are
in [office-docx-read.md](office-docx-read.md).
The structured read commands dispatch by validated package content and share
canonical `office.selector/1` paths. Full command, selector, limit, and
error-code details are in [office-docx-read.md](office-docx-read.md) and
[office-xlsx-read.md](office-xlsx-read.md).

### `office.docx.outline/1` (`office outline FILE --json`)

Expand Down Expand Up @@ -500,6 +509,84 @@ evaluated. `ignore_case` applies locale-independent Unicode simple lowercase
mapping to the text predicate (one scalar to one scalar, without locale
tailoring or multi-character expansion).

### `office.xlsx.outline/1` (`office outline FILE --json`)

| key | type | notes |
| --- | --- | --- |
| `schema` | string | `"office.xlsx.outline/1"` |
| `file`, `format` | string | input path and literal `"xlsx"` |
| `path` | string | stable `/xlsx/workbook` |
| `sheet_count` | number | exact tab-order sheet count |
| `active_sheet` | object? | `{path, name, index}` when the workbook has sheets |
| `sheets` | array | tab-order worksheet/chart-sheet summaries |
| `defined_names` | array | `{name, refers_to, scope?, comment?}` |
| `limits` | object | effective cell-scan and metadata ceilings |

Every sheet summary has canonical `path`, `name`, 1-based `index`, `kind`,
`state`, and `counts`. Worksheets additionally expose `max_row`, `max_column`,
and optional `used_range: {path, reference, cell_count}`. Worksheet counts
cover merges, tables, charts, images, pivots, comments, hyperlinks, data
validations, conditional-format ranges, and slicers. Chart sheets report their
chart count. State is `visible`, `hidden`, or `very_hidden`.

### `office.xlsx.element/1` (`office get FILE SELECTOR --json`)

Common keys are `schema`, `file`, literal `format: "xlsx"`, canonical `path`,
`kind`, and `stability`. Kind-specific members are:

| kind | members |
| --- | --- |
| `workbook` | `sheet_count`, `sheets`, and `defined_names` |
| `sheet` | one `sheet` summary |
| `cell` | stable sheet `parent`, `cell`, `styles`, and `scanned_cells` |
| `range` | sheet `parent`, normalized `reference`, populated `cells`, `styles`, `scanned_cells`, and `returned` |

Cell records contain canonical `path`, A1 `reference`, 1-based `row` and
`column`, optional displayed `value`, optional typed `raw: {type, value}`,
optional formula text without `=`, and optional nonzero `style_id`. Raw types
are `string`, `number`, `bool`, and `error`. `styles` is an object keyed by
referenced style ids. Range cells are row-major and omit completely blank,
unstyled coordinates.

### `office.xlsx.text/1` (`office text FILE ... --json`)

| key | type | notes |
| --- | --- | --- |
| `schema` | string | `"office.xlsx.text/1"` |
| `file`, `format` | string | input path and literal `"xlsx"` |
| `under` | string? | resolved canonical workbook/sheet/cell/range scope |
| `entries` | array | `{path, stability, text}` in tab/row/column order |
| `matched_total` | number | exact count after the completed bounded scan |
| `offset`, `limit`, `returned` | number | explicit pagination |
| `truncated` | boolean | later matches were omitted |
| `scanned_cells` | number | coordinates inspected |

`text` is the displayed value. A formula without a cached display value falls
back to its formula text prefixed with `=`.

### `office.xlsx.query/1` (`office query FILE [CELL_SELECTOR] ... --json`)

| key | type | notes |
| --- | --- | --- |
| `schema` | string | `"office.xlsx.query/1"` |
| `file`, `format` | string | input path and literal `"xlsx"` |
| `under` | string? | resolved canonical workbook/sheet/cell/range scope |
| `selector` | string | the supplied `cell[predicate]...` selector, or default `cell` |
| `matches` | array | row-major cell records in the same shape as `get` |
| `styles` | object | effective styles referenced by returned matches |
| `matched_total` | number | exact count after the completed bounded scan |
| `offset`, `limit`, `returned` | number | explicit pagination |
| `truncated` | boolean | later matches were omitted |
| `scanned_cells` | number | coordinates inspected |

Predicates are literal and ANDed: `type=formula|number|string|bool|error`,
`formula`, `formula~=TEXT`, `text=TEXT`, `text~=TEXT`, and numeric
`value>NUMBER` comparisons (`>=`, `<`, `<=`, `=`, and `!=` are also
supported). Substring predicates are guaranteed-linear and command-work
bounded. Text literals preserve whitespace exactly; a JSON-string literal can
represent closing brackets and escaped characters. No regular expression or
arbitrary expression is evaluated.

## Standalone `docx` CLI schemas

## `docx.outline/1` — document structure map (`docx outline <file>`)
Expand Down
8 changes: 5 additions & 3 deletions docs/office-docx-read.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ moon run office/cmd/office -- query report.docx --kind paragraph --text revenue

Run `office help docx` for the installed command catalog and
`office help <command> --json` for the declared inputs, outputs, and bounds.
These commands accept DOCX packages only. Passing an XLSX package fails with
`office.unsupported_operation`; XLSX selector resolution remains a later
milestone.
The file's validated package format selects the result contract. This document
covers the DOCX branch; passing an XLSX package invokes the corresponding XLSX
read contract in [office-xlsx-read.md](office-xlsx-read.md). Passing an
`/xlsx/...` selector to a DOCX package fails with
`office.docx.selector_format_mismatch`.

## Output envelope

Expand Down
Loading
Loading