class_docstr: Transforms field lists in "doc field" syntax into better-looking
  equivalents, using the field type definitions given on a domain.
class_docstr_tok: ["Transforms","field","lists","in","``","doc","field","''","syntax","into","better-looking","equivalents",",","using","the","field","type","definitions","given","on","a","domain","."]
docstr: Transform a single field list *node*.
docstr_tok: ["Transform","a","single","field","list","*","node","*","."]
code: def transform(self, node: nodes.field_list) -> None:
      """Transform a single field list *node*."""
      typemap = self.typemap
  
      entries: list[nodes.field | tuple[Field, Any, Element]] = []
      groupindices: dict[str, int] = {}
      types: dict[str, dict] = {}
  
      # step 1: traverse all fields and collect field types and content
      for field in cast(list[nodes.field], node):
          assert len(field) == 2
          field_name = cast(nodes.field_name, field[0])
          field_body = cast(nodes.field_body, field[1])
          try:
              # split into field type and argument
              fieldtype_name, fieldarg = field_name.astext().split(
                  None, 1
              )
          except ValueError:
              # maybe an argument-less field type?
              fieldtype_name, fieldarg = field_name.astext(), ""
          typedesc, is_typefield = typemap.get(
              fieldtype_name, (None, None)
          )
  
          # collect the content, trying not to keep unnecessary paragraphs
          if _is_single_paragraph(field_body):
              paragraph = cast(nodes.paragraph, field_body[0])
              content = paragraph.children
          else:
              content = field_body.children
  
          # sort out unknown fields
          if typedesc is None or typedesc.has_arg != bool(fieldarg):
              # either the field name is unknown, or the argument doesn't
              # match the spec; capitalize field name and be done with it
              new_fieldname = (
                  fieldtype_name[0:1].upper() + fieldtype_name[1:]
              )
              if fieldarg:
                  new_fieldname += " " + fieldarg
              field_name[0] = nodes.Text(new_fieldname)
              entries.append(field)
  
              # but if this has a type then we can at least link it
              if (
                  typedesc
                  and is_typefield
                  and content
                  and len(content) == 1
                  and isinstance(content[0], nodes.Text)
              ):
                  typed_field = cast(TypedField, typedesc)
                  target = content[0].astext()
                  xrefs = typed_field.make_xrefs(
                      typed_field.typerolename,
                      self.directive.domain or "",
                      target,
                      contnode=content[0],
                      env=self.directive.state.document.settings.env,
                  )
                  if _is_single_paragraph(field_body):
                      paragraph = cast(nodes.paragraph, field_body[0])
                      paragraph.clear()
                      paragraph.extend(xrefs)
                  else:
                      field_body.clear()
                      field_body += nodes.paragraph("", "", *xrefs)
  
              continue
  
          typename = typedesc.name
  
          # if the field specifies a type, put it in the types collection
          if is_typefield:
              # filter out only inline nodes; others will result in invalid
              # markup being written out
              content = [
                  n
                  for n in content
                  if isinstance(n, (nodes.Inline, nodes.Text))
              ]
              if content:
                  types.setdefault(typename, {})[fieldarg] = content
              continue
  
          # also support syntax like ``:param type name:``
          if typedesc.is_typed:
              try:
                  argtype, argname = fieldarg.rsplit(None, 1)
              except ValueError:
                  pass
              else:
                  types.setdefault(typename, {})[argname] = [
                      nodes.Text(argtype)
                  ]
                  fieldarg = argname
  
          translatable_content = nodes.inline(
              field_body.rawsource, translatable=True
          )
          translatable_content.document = field_body.parent.document
          translatable_content.source = field_body.parent.source
          translatable_content.line = field_body.parent.line
          translatable_content += content
  
          # grouped entries need to be collected in one entry, while others
          # get one entry per field
          if typedesc.is_grouped:
              if typename in groupindices:
                  group = cast(
                      tuple[Field, list, Node],
                      entries[groupindices[typename]],
                  )
              else:
                  groupindices[typename] = len(entries)
                  group = (typedesc, [], field)
                  entries.append(group)
              new_entry = typedesc.make_entry(
                  fieldarg, [translatable_content]
              )
              group[1].append(new_entry)
          else:
              new_entry = typedesc.make_entry(
                  fieldarg, [translatable_content]
              )
              entries.append((typedesc, new_entry, field))
  
      # step 2: all entries are collected, construct the new field list
      new_list = nodes.field_list()
      for entry in entries:
          if isinstance(entry, nodes.field):
              # pass-through old field
              new_list += entry
          else:
              fieldtype, items, location = entry
              fieldtypes = types.get(fieldtype.name, {})
              env = self.directive.state.document.settings.env
              inliner = self.directive.state.inliner
              domain = self.directive.domain or ""
              new_list += fieldtype.make_field(
                  fieldtypes,
                  domain,
                  items,
                  env=env,
                  inliner=inliner,
                  location=location,
              )
  
      node.replace_self(new_list)
  
imports: from __future__ import annotations
  import contextlib
  from typing import TYPE_CHECKING, Any, cast
  from docutils import nodes
  from docutils.nodes import Element, Node
  from sphinx import addnodes
  from sphinx.locale import __
  from sphinx.util import logging
  from sphinx.util.nodes import get_node_line
label_desc: Use image node_id 3 for calling the DocFieldTransformer obj's underlying member method code with example usage: obj.transform(node) without return types