docx/field-type

A family covering 30 common Word field instruction codes carried as simple fields (w:fldSimple).

Cases (30)

Feature IDAxis bindingspython-docxdocxjs
docx/field-type--authorfield=author
docx/field-type--commentsfield=comments
docx/field-type--createdatefield=createdate
docx/field-type--datefield=date
docx/field-type--docpropertyfield=docproperty
docx/field-type--filenamefield=filename
docx/field-type--hyperlinkfield=hyperlink
docx/field-type--iffield=if
docx/field-type--includetextfield=includetext
docx/field-type--keywordsfield=keywords
docx/field-type--mergefieldfield=mergefield
docx/field-type--numcharsfield=numchars
docx/field-type--numpagesfield=numpages
docx/field-type--numwordsfield=numwords
docx/field-type--pagefield=page
docx/field-type--pagereffield=pageref
docx/field-type--printdatefield=printdate
docx/field-type--reffield=ref
docx/field-type--savedatefield=savedate
docx/field-type--sectionfield=section
docx/field-type--sectionpagesfield=sectionpages
docx/field-type--seqfield=seq
docx/field-type--stylereffield=styleref
docx/field-type--subjectfield=subject
docx/field-type--symbolfield=symbol
docx/field-type--templatefield=template
docx/field-type--timefield=time
docx/field-type--titlefield=title
docx/field-type--userinitialsfield=userinitials
docx/field-type--usernamefield=username

Aggregate

LibraryPassFailPending
python-docx0030
docxjs0030

Parameter axes

Spec notes

Each expanded case emits a single <w:fldSimple w:instr="..."> carrying a distinct field instruction code (PAGE, DATE, AUTHOR, HYPERLINK, IF, ...). The cached result is written as the child <w:t>; Word refreshes it on open if the field is marked dirty. This manifest expands into 30 concrete test cases, one per field instruction, each backed by fixture docx/field-type--<id>.docx generated from gen_field_type.py. Cached values are intentionally not asserted — some instructions (COMMENTS, INCLUDETEXT) carry an empty cached result. The assertion pins w:instr verbatim; python-docx serialises the inner double-quotes as &quot; inside the attribute, which is unescaped back to " when the XML parser reads @w:instr.

Generator source

scripts/gen_field_type.py — runs with --arg_template --instr '{field.instr}' --cached '{field.cached}' --out fixtures/docx/field-type--{field.id}.docx

#!/usr/bin/env python3
"""Generate a ``fixtures/docx/field-type--<id>.docx`` fixture.

Parameterised generator for the ``docx/field-type`` feature family.
Emits a single paragraph containing one ``w:fldSimple`` element carrying
the Word field instruction supplied via ``--instr`` and the cached
result text supplied via ``--cached``. The cached value is written as
the field's child run text; Word refreshes it on open if the field is
marked dirty. Consumed by ``features/docx/field-type.json``'s
``generator.arg_template``.
"""

from __future__ import annotations

import argparse
from pathlib import Path

from docx import Document

_REPO_ROOT = Path(__file__).resolve().parent.parent


def _write(instr: str, cached: str, out: Path) -> None:
    doc = Document()
    paragraph = doc.add_paragraph()
    # ``text=None`` for empty cached results so python-docx omits the
    # inner ``<w:t>`` rather than writing an empty one.
    paragraph.add_simple_field(instr, text=cached or None)
    out.parent.mkdir(parents=True, exist_ok=True)
    doc.save(out, reproducible=True)


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--instr", required=True, help="Word field instruction, e.g. 'PAGE \\* MERGEFORMAT'")
    parser.add_argument("--cached", default="", help="Cached result text (may be empty)")
    parser.add_argument("--out", required=True, help="Output .docx path (absolute or repo-relative)")
    args = parser.parse_args()

    out_path = Path(args.out)
    if not out_path.is_absolute():
        out_path = _REPO_ROOT / out_path
    _write(args.instr, args.cached, out_path)
    print(out_path)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Manifest (parent, unexpanded)

{
  "$schema": "../manifest.schema.json",
  "id": "docx/field-type",
  "kind": "parameterised",
  "title": "Field: instruction types",
  "format": "docx",
  "category": "fields",
  "summary": "A family covering 30 common Word field instruction codes carried as simple fields (w:fldSimple).",
  "spec": {
    "source": "ecma-376-5-part-1",
    "clause": "17.16.5",
    "element": "w:fldSimple",
    "rnc_reference": "spec/ecma-376-5/part-1/rnc/WordprocessingML.rnc",
    "xsd_reference": "spec/ecma-376-5/part-1/xsd/wml.xsd",
    "notes": "Each expanded case emits a single <w:fldSimple w:instr=\"...\"> carrying a distinct field instruction code (PAGE, DATE, AUTHOR, HYPERLINK, IF, ...). The cached result is written as the child <w:t>; Word refreshes it on open if the field is marked dirty. This manifest expands into 30 concrete test cases, one per field instruction, each backed by fixture docx/field-type--<id>.docx generated from gen_field_type.py. Cached values are intentionally not asserted — some instructions (COMMENTS, INCLUDETEXT) carry an empty cached result. The assertion pins w:instr verbatim; python-docx serialises the inner double-quotes as &quot; inside the attribute, which is unescaped back to \" when the XML parser reads @w:instr."
  },
  "fixtures": {
    "machine": "docx/field-type",
    "office": "docx/field-type"
  },
  "generator": {
    "python": "scripts/gen_field_type.py",
    "arg_template": "--instr '{field.instr}' --cached '{field.cached}' --out fixtures/docx/field-type--{field.id}.docx"
  },
  "parameters": {
    "field": [
      {
        "id": "page",
        "instr": "PAGE \\* MERGEFORMAT",
        "cached": "1"
      },
      {
        "id": "numpages",
        "instr": "NUMPAGES \\* MERGEFORMAT",
        "cached": "1"
      },
      {
        "id": "date",
        "instr": "DATE \\@ \"yyyy-MM-dd\"",
        "cached": "2026-01-01"
      },
      {
        "id": "time",
        "instr": "TIME \\@ \"HH:mm\"",
        "cached": "12:00"
      },
      {
        "id": "author",
        "instr": "AUTHOR \\* MERGEFORMAT",
        "cached": "User"
      },
      {
        "id": "title",
        "instr": "TITLE \\* MERGEFORMAT",
        "cached": "Document Title"
      },
      {
        "id": "subject",
        "instr": "SUBJECT \\* MERGEFORMAT",
        "cached": "Subject"
      },
      {
        "id": "keywords",
        "instr": "KEYWORDS \\* MERGEFORMAT",
        "cached": "keyword"
      },
      {
        "id": "comments",
        "instr": "COMMENTS \\* MERGEFORMAT",
        "cached": ""
      },
      {
        "id": "filename",
        "instr": "FILENAME \\* MERGEFORMAT",
        "cached": "document.docx"
      },
      {
        "id": "hyperlink",
        "instr": "HYPERLINK \"https://example.com\"",
        "cached": "link"
      },
      {
        "id": "userinitials",
        "instr": "USERINITIALS \\* MERGEFORMAT",
        "cached": "U"
      },
      {
        "id": "username",
        "instr": "USERNAME \\* MERGEFORMAT",
        "cached": "User Name"
      },
      {
        "id": "createdate",
        "instr": "CREATEDATE \\@ \"yyyy-MM-dd\"",
        "cached": "2026-01-01"
      },
      {
        "id": "savedate",
        "instr": "SAVEDATE \\@ \"yyyy-MM-dd\"",
        "cached": "2026-01-01"
      },
      {
        "id": "printdate",
        "instr": "PRINTDATE \\@ \"yyyy-MM-dd\"",
        "cached": "2026-01-01"
      },
      {
        "id": "numchars",
        "instr": "NUMCHARS \\* MERGEFORMAT",
        "cached": "100"
      },
      {
        "id": "numwords",
        "instr": "NUMWORDS \\* MERGEFORMAT",
        "cached": "20"
      },
      {
        "id": "section",
        "instr": "SECTION \\* MERGEFORMAT",
        "cached": "1"
      },
      {
        "id": "sectionpages",
        "instr": "SECTIONPAGES \\* MERGEFORMAT",
        "cached": "1"
      },
      {
        "id": "ref",
        "instr": "REF bookmark1 \\h",
        "cached": "Bookmarked text"
      },
      {
        "id": "pageref",
        "instr": "PAGEREF bookmark1 \\h",
        "cached": "1"
      },
      {
        "id": "mergefield",
        "instr": "MERGEFIELD Name",
        "cached": "FirstName"
      },
      {
        "id": "docproperty",
        "instr": "DOCPROPERTY Title",
        "cached": "Document Title"
      },
      {
        "id": "template",
        "instr": "TEMPLATE \\* MERGEFORMAT",
        "cached": "Normal.dotm"
      },
      {
        "id": "styleref",
        "instr": "STYLEREF \"Heading 1\" \\* MERGEFORMAT",
        "cached": "Heading"
      },
      {
        "id": "includetext",
        "instr": "INCLUDETEXT \"other.docx\"",
        "cached": ""
      },
      {
        "id": "seq",
        "instr": "SEQ figure \\* ARABIC",
        "cached": "1"
      },
      {
        "id": "symbol",
        "instr": "SYMBOL 65 \\f \"Arial\"",
        "cached": "A"
      },
      {
        "id": "if",
        "instr": "IF 1 = 1 \"yes\" \"no\"",
        "cached": "yes"
      }
    ]
  },
  "assertions_template": [
    {
      "id": "field-instr-{field.id}",
      "part": "word/document.xml",
      "namespaces": {
        "w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
      },
      "xpath": "//w:fldSimple/@w:instr",
      "must": "equal",
      "value": "{field.instr}",
      "description": "The fixture must contain a <w:fldSimple> whose w:instr attribute equals the expected field instruction verbatim. Uses `must: equal` (literal string compare) rather than `match` because several instructions carry backslash-escape sequences (\\*, \\@, \\h, \\f) that would require regex-escaping to embed in the manifest."
    }
  ]
}