#!/bin/bash # numbering.sh — exercise every supported `num` / `abstractNum` feature. # # Builds a single .docx that demonstrates: # • abstractNum top-level props: name, styleLink, numStyleLink, multiLevelType # • Per-level dotted props on all 9 levels: format, text, start, indent, # hanging, justification, suff, font, size, color, bold, italic # • num mode A (auto-create matching abstractNum from format/text/indent) # • num mode B (reuse existing abstractNum via abstractNumId) # • num mode C (lvlOverride.start — restart numbering for one instance) # • Two num instances sharing one abstractNum → independent counters # • style-borne numPr (Heading-style multi-level outline) # • Set on /numbering/abstractNum[@id=N]/level[L] after creation # NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script # tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and # keeps building so the full document is produced. DOCX="$(dirname "$0")/numbering.docx" echo "Building $DOCX ..." rm -f "$DOCX" officecli create "$DOCX" # ============================================================ # Title # ============================================================ officecli add "$DOCX" /body --type paragraph \ --prop "text=Numbering & List Showcase" --prop align=center \ --prop bold=true --prop size=20 officecli add "$DOCX" /body --type paragraph \ --prop "text=Generated by officecli — covers abstractNum, num, and style-borne numPr" \ --prop align=center --prop italic=true --prop color=666666 officecli add "$DOCX" /body --type paragraph --prop "text=" # ============================================================ # Section 1: abstractNum #100 — fully customized 3-level numbered template # Level 0: decimal, red bold, 14pt — "1." # Level 1: lowerLetter, blue italic — "a)" # Level 2: lowerRoman gray — "i." # Levels 3-8: auto-fallback cycle # ============================================================ officecli add "$DOCX" /body --type paragraph \ --prop "text=1. Three-level numbered list (custom marker styling)" \ --prop bold=true --prop size=14 --prop spaceBefore=240 --prop spaceAfter=120 officecli add "$DOCX" /numbering --type abstractNum \ --prop id=100 \ --prop "name=ShowcaseMultilevel" \ --prop type=hybridMultilevel \ --prop "level0.format=decimal" \ --prop "level0.text=%1." \ --prop "level0.indent=720" \ --prop "level0.hanging=360" \ --prop "level0.justification=left" \ --prop "level0.suff=tab" \ --prop "level0.color=C00000" \ --prop "level0.bold=true" \ --prop "level0.size=14" \ --prop "level1.format=lowerLetter" \ --prop "level1.text=%2)" \ --prop "level1.indent=1440" \ --prop "level1.hanging=360" \ --prop "level1.color=2E74B5" \ --prop "level1.italic=true" \ --prop "level2.format=lowerRoman" \ --prop "level2.text=%3." \ --prop "level2.indent=2160" \ --prop "level2.hanging=360" \ --prop "level2.color=666666" # A num instance pointing at #100 NUMID_A=$(officecli add "$DOCX" /numbering --type num --prop abstractNumId=100 \ | sed -n 's|.*@id=\([0-9]*\)\].*|\1|p') echo " Created num #$NUMID_A → abstractNum #100" officecli add "$DOCX" /body --type paragraph \ --prop "text=Project Phoenix kickoff agenda" \ --prop "numId=$NUMID_A" --prop ilvl=0 officecli add "$DOCX" /body --type paragraph \ --prop "text=Stakeholder alignment" \ --prop "numId=$NUMID_A" --prop ilvl=1 officecli add "$DOCX" /body --type paragraph \ --prop "text=identify decision makers" \ --prop "numId=$NUMID_A" --prop ilvl=2 officecli add "$DOCX" /body --type paragraph \ --prop "text=schedule discovery interviews" \ --prop "numId=$NUMID_A" --prop ilvl=2 officecli add "$DOCX" /body --type paragraph \ --prop "text=Architecture review" \ --prop "numId=$NUMID_A" --prop ilvl=1 officecli add "$DOCX" /body --type paragraph \ --prop "text=Sprint planning" \ --prop "numId=$NUMID_A" --prop ilvl=0 officecli add "$DOCX" /body --type paragraph \ --prop "text=Resource allocation" \ --prop "numId=$NUMID_A" --prop ilvl=0 # ============================================================ # Section 2: Independent counters (default) vs Word-style continuation # Two new nums on the same abstractNum: by default each gets its own # auto-injected startOverride.0 → counters are independent. The third # num passes --prop continue=true to opt into Word's literal "continue # from previous num" behavior. # ============================================================ officecli add "$DOCX" /body --type paragraph --prop "text=" officecli add "$DOCX" /body --type paragraph \ --prop "text=2. Independent counters (default) and continue=true opt-in" \ --prop bold=true --prop size=14 --prop spaceBefore=240 --prop spaceAfter=120 NUMID_B=$(officecli add "$DOCX" /numbering --type num --prop abstractNumId=100 \ | sed -n 's|.*@id=\([0-9]*\)\].*|\1|p') echo " Created num #$NUMID_B → independent counter (auto-injected startOverride.0=1)" NUMID_CONT=$(officecli add "$DOCX" /numbering --type num \ --prop abstractNumId=100 --prop continue=true \ | sed -n 's|.*@id=\([0-9]*\)\].*|\1|p') echo " Created num #$NUMID_CONT → Word-style continuation (continue=true)" officecli add "$DOCX" /body --type paragraph \ --prop "text=List B starts fresh at 1 (default behavior)" \ --prop "numId=$NUMID_B" --prop ilvl=0 officecli add "$DOCX" /body --type paragraph \ --prop "text=List B item two (counts 2)" \ --prop "numId=$NUMID_B" --prop ilvl=0 officecli add "$DOCX" /body --type paragraph \ --prop "text=List C continues from List A's count (continue=true)" \ --prop "numId=$NUMID_CONT" --prop ilvl=0 officecli add "$DOCX" /body --type paragraph \ --prop "text=List C item two" \ --prop "numId=$NUMID_CONT" --prop ilvl=0 # ============================================================ # Section 3: Mode C — num with lvlOverride.start (restart at 100) # ============================================================ officecli add "$DOCX" /body --type paragraph --prop "text=" officecli add "$DOCX" /body --type paragraph \ --prop "text=3. Restart numbering with startOverride" \ --prop bold=true --prop size=14 --prop spaceBefore=240 --prop spaceAfter=120 NUMID_C=$(officecli add "$DOCX" /numbering --type num \ --prop abstractNumId=100 --prop start=100 \ | sed -n 's|.*@id=\([0-9]*\)\].*|\1|p') echo " Created num #$NUMID_C → abstractNum #100 with startOverride.0=100" officecli add "$DOCX" /body --type paragraph \ --prop "text=Numbered starting from 100" \ --prop "numId=$NUMID_C" --prop ilvl=0 officecli add "$DOCX" /body --type paragraph \ --prop "text=Continues from 101" \ --prop "numId=$NUMID_C" --prop ilvl=0 # ============================================================ # Section 4: Bullet list with custom glyphs and font color # ============================================================ officecli add "$DOCX" /body --type paragraph --prop "text=" officecli add "$DOCX" /body --type paragraph \ --prop "text=4. Custom-styled bullet list (★ / ▶ / ●)" \ --prop bold=true --prop size=14 --prop spaceBefore=240 --prop spaceAfter=120 officecli add "$DOCX" /numbering --type abstractNum \ --prop id=200 \ --prop "name=StarBullet" \ --prop type=hybridMultilevel \ --prop "level0.format=bullet" --prop "level0.text=★" \ --prop "level0.color=E8B003" --prop "level0.size=12" \ --prop "level1.format=bullet" --prop "level1.text=▶" \ --prop "level1.font=Arial" \ --prop "level1.color=2E74B5" --prop "level1.indent=1440" \ --prop "level2.format=bullet" --prop "level2.text=●" \ --prop "level2.color=70AD47" --prop "level2.indent=2160" NUMID_BULLET=$(officecli add "$DOCX" /numbering --type num --prop abstractNumId=200 \ | sed -n 's|.*@id=\([0-9]*\)\].*|\1|p') officecli add "$DOCX" /body --type paragraph \ --prop "text=Top-level milestone" \ --prop "numId=$NUMID_BULLET" --prop ilvl=0 officecli add "$DOCX" /body --type paragraph \ --prop "text=Sub-milestone with deliverable" \ --prop "numId=$NUMID_BULLET" --prop ilvl=1 officecli add "$DOCX" /body --type paragraph \ --prop "text=Nitty-gritty detail" \ --prop "numId=$NUMID_BULLET" --prop ilvl=2 officecli add "$DOCX" /body --type paragraph \ --prop "text=Another top-level milestone" \ --prop "numId=$NUMID_BULLET" --prop ilvl=0 # ============================================================ # Section 5: Mode A — num auto-creates abstractNum on the fly # ============================================================ officecli add "$DOCX" /body --type paragraph --prop "text=" officecli add "$DOCX" /body --type paragraph \ --prop "text=5. Mode A — num auto-creates abstractNum" \ --prop bold=true --prop size=14 --prop spaceBefore=240 --prop spaceAfter=120 NUMID_AUTO=$(officecli add "$DOCX" /numbering --type num \ --prop "level0.format=upperRoman" --prop "level0.text=%1." \ --prop "level0.indent=720" --prop "level0.size=12" \ --prop "level0.color=7030A0" --prop "level0.bold=true" \ | sed -n 's|.*@id=\([0-9]*\)\].*|\1|p') echo " Mode A created num #$NUMID_AUTO + matching abstractNum" officecli add "$DOCX" /body --type paragraph \ --prop "text=The first part of the proposal" \ --prop "numId=$NUMID_AUTO" --prop ilvl=0 officecli add "$DOCX" /body --type paragraph \ --prop "text=The second part" \ --prop "numId=$NUMID_AUTO" --prop ilvl=0 officecli add "$DOCX" /body --type paragraph \ --prop "text=The third part" \ --prop "numId=$NUMID_AUTO" --prop ilvl=0 # ============================================================ # Section 6: Style-borne numPr — paragraphs inherit numbering via pStyle # ============================================================ officecli add "$DOCX" /body --type paragraph --prop "text=" officecli add "$DOCX" /body --type paragraph \ --prop "text=6. Style-borne numbering (paragraph inherits via pStyle)" \ --prop bold=true --prop size=14 --prop spaceBefore=240 --prop spaceAfter=120 # Build a dedicated abstractNum + num for this style officecli add "$DOCX" /numbering --type abstractNum \ --prop id=300 --prop "name=StyleBorne" \ --prop "level0.format=decimalZero" --prop "level0.text=%1." \ --prop "level0.indent=720" --prop "level0.color=C00000" NUMID_STYLE=$(officecli add "$DOCX" /numbering --type num --prop abstractNumId=300 \ | sed -n 's|.*@id=\([0-9]*\)\].*|\1|p') # Style holds the numPr; paragraphs reference the style without their own numId officecli add "$DOCX" /styles --type style \ --prop id=ShowcaseListItem \ --prop "name=Showcase List Item" \ --prop type=paragraph \ --prop basedOn=Normal \ --prop "numId=$NUMID_STYLE" --prop ilvl=0 officecli add "$DOCX" /body --type paragraph \ --prop "text=Inherits numbering through style" \ --prop style=ShowcaseListItem officecli add "$DOCX" /body --type paragraph \ --prop "text=Second item, also via style" \ --prop style=ShowcaseListItem officecli add "$DOCX" /body --type paragraph \ --prop "text=Third item — note: paragraphs themselves have no numPr" \ --prop style=ShowcaseListItem # ============================================================ # Section 7: Set after create — modify abstractNum #100 level 3 # ============================================================ officecli add "$DOCX" /body --type paragraph --prop "text=" officecli add "$DOCX" /body --type paragraph \ --prop "text=7. Modify abstractNum after creation" \ --prop bold=true --prop size=14 --prop spaceBefore=240 --prop spaceAfter=120 # Override level 3 (deepest reached in section 1) with green color + larger size officecli set "$DOCX" '/numbering/abstractNum[@id=100]/level[3]' \ --prop format=decimal --prop "text=Step %4 ⇒" \ --prop color=70AD47 --prop bold=true --prop size=12 NUMID_DEEP=$(officecli add "$DOCX" /numbering --type num --prop abstractNumId=100 \ | sed -n 's|.*@id=\([0-9]*\)\].*|\1|p') officecli add "$DOCX" /body --type paragraph \ --prop "text=Outer step" \ --prop "numId=$NUMID_DEEP" --prop ilvl=0 officecli add "$DOCX" /body --type paragraph \ --prop "text=Mid step" \ --prop "numId=$NUMID_DEEP" --prop ilvl=1 officecli add "$DOCX" /body --type paragraph \ --prop "text=Inner step" \ --prop "numId=$NUMID_DEEP" --prop ilvl=2 officecli add "$DOCX" /body --type paragraph \ --prop "text=Deepest step (modified after creation)" \ --prop "numId=$NUMID_DEEP" --prop ilvl=3 # ============================================================ # Section 8: Missing property coverage # • abstractNum: styleLink, numStyleLink, level.start # • level Set: direction (rtl), isLgl, lvlRestart # ============================================================ officecli add "$DOCX" /body --type paragraph --prop "text=" officecli add "$DOCX" /body --type paragraph \ --prop "text=8. styleLink, numStyleLink, level.start, direction, isLgl, lvlRestart" \ --prop bold=true --prop size=14 --prop spaceBefore=240 --prop spaceAfter=120 # abstractNum with styleLink + numStyleLink + level2.start (all 3 Add-only keys missing before) officecli add "$DOCX" /numbering --type abstractNum \ --prop id=400 \ --prop "name=CoverageAbs" \ --prop type=multilevel \ --prop "styleLink=CoverageStyle" \ --prop "numStyleLink=OutlineRef" \ --prop "level0.format=decimal" --prop "level0.text=%1." \ --prop "level0.start=1" \ --prop "level1.format=lowerLetter" --prop "level1.text=%2)" \ --prop "level1.start=3" \ --prop "level2.format=lowerRoman" --prop "level2.text=%3." \ --prop "level2.start=5" # Set direction=rtl, isLgl=true, lvlRestart=0 on individual levels via Set officecli set "$DOCX" '/numbering/abstractNum[@id=400]/level[1]' \ --prop direction=rtl officecli set "$DOCX" '/numbering/abstractNum[@id=400]/level[2]' \ --prop isLgl=true --prop lvlRestart=0 NUMID_COV=$(officecli add "$DOCX" /numbering --type num --prop abstractNumId=400 \ | sed -n 's|.*@id=\([0-9]*\)\].*|\1|p') echo " Created num #$NUMID_COV → abstractNum #400 (coverage)" officecli add "$DOCX" /body --type paragraph \ --prop "text=Item starting at 1 (level0.start=1)" \ --prop "numId=$NUMID_COV" --prop ilvl=0 officecli add "$DOCX" /body --type paragraph \ --prop "text=Sub-item starting at c (level1.start=3, direction=rtl)" \ --prop "numId=$NUMID_COV" --prop ilvl=1 officecli add "$DOCX" /body --type paragraph \ --prop "text=Deep item starting at v (level2.start=5, isLgl, lvlRestart=0)" \ --prop "numId=$NUMID_COV" --prop ilvl=2 # ============================================================ # Closer # ============================================================ officecli add "$DOCX" /body --type paragraph --prop "text=" officecli add "$DOCX" /body --type paragraph \ --prop "text=End of showcase. Open in Word/Google Docs to see all numbering rendered." \ --prop italic=true --prop color=666666 --prop align=center officecli close "$DOCX" officecli validate "$DOCX" echo "" echo "Done. Output: $DOCX" echo "" echo "Summary of generated definitions:" officecli query "$DOCX" /numbering 2>/dev/null | head -5 || true echo "" echo " abstractNum #100 (ShowcaseMultilevel) — used by num #$NUMID_A, #$NUMID_B, #$NUMID_C, #$NUMID_DEEP" echo " abstractNum #200 (StarBullet) — used by num #$NUMID_BULLET" echo " abstractNum #300 (StyleBorne) — used by num #$NUMID_STYLE (via ShowcaseListItem style)" echo " abstractNum #auto — used by num #$NUMID_AUTO (mode A)" echo " abstractNum #400 (CoverageAbs) — styleLink, numStyleLink, level.start, direction, isLgl, lvlRestart"