2222from metaobjects .meta .meta_data import MetaData
2323from metaobjects .meta .template .template_constants import TEMPLATE_ATTR_XML_TEXT
2424from metaobjects .shared .base_types import TYPE_FIELD
25- from metaobjects .shared .structural import KEY_IS_ARRAY
2625
2726
2827def fields (vo : MetaData ) -> list [MetaData ]:
@@ -32,9 +31,10 @@ def fields(vo: MetaData) -> list[MetaData]:
3231
3332
3433def is_array (field : MetaData ) -> bool :
35- """Array-ness from either form: the node property (programmatic build) or the
36- ``@isArray`` attr (how metadata loads from JSON)."""
37- return bool (field .is_array ) or field .attrs ().get (KEY_IS_ARRAY ) is True
34+ """Effective array-ness (ADR-0039 resolving): the native ``is_array`` flag OR the
35+ ``@isArray`` attr, resolved through the ``extends`` super chain so a concrete field
36+ inheriting array-ness from an abstract parent is honored."""
37+ return field .resolved_is_array ()
3838
3939
4040def is_required (field : MetaData ) -> bool :
@@ -63,31 +63,36 @@ def enum_values(field: MetaData) -> list[str]:
6363 return []
6464
6565
66- def _own_attr_string (node : MetaData , name : str ) -> str | None :
67- """The own (locally declared) string value of attr *name*, or ``None``."""
68- v = node .attr (name )
66+ def _attr_string (node : MetaData , name : str ) -> str | None :
67+ """The RESOLVING string value of attr *name* (own + inherited via ``extends``),
68+ or ``None``.
69+
70+ ADR-0039 — effective read: a concrete enum field extending an abstract enum may
71+ inherit ``@coerceDefault``/``@default``/``@normalize`` from the abstract parent,
72+ so these resolve through the super chain (``get_meta_attr``), never own-only."""
73+ v = node .get_meta_attr (name )
6974 return v if isinstance (v , str ) else None
7075
7176
7277def coerce_default (field : MetaData ) -> str | None :
73- """FR-011: the enum field's own ``@coerceDefault`` member, or ``None``."""
74- return _own_attr_string (field , fc .FIELD_ATTR_COERCE_DEFAULT )
78+ """FR-011: the enum field's effective ``@coerceDefault`` member, or ``None``."""
79+ return _attr_string (field , fc .FIELD_ATTR_COERCE_DEFAULT )
7580
7681
7782def default_value (field : MetaData ) -> str | None :
78- """FR-011: the enum field's own ``@default`` absent-fill member, or ``None``."""
79- return _own_attr_string (field , fc .FIELD_ATTR_DEFAULT )
83+ """FR-011: the enum field's effective ``@default`` absent-fill member, or ``None``."""
84+ return _attr_string (field , fc .FIELD_ATTR_DEFAULT )
8085
8186
8287def resolve_normalize (field : MetaData , owner : MetaData | None ) -> str :
8388 """FR-011: resolve the enum normalization mode — field-level ``@normalize``, else the
8489 owning ``object.value``'s ``@normalize`` (the per-object default), else the global
8590 default (``"strip"``). Mirrors the Java/Kotlin/C#/TS ``resolveNormalize``."""
86- field_mode = _own_attr_string (field , fc .FIELD_ATTR_NORMALIZE )
91+ field_mode = _attr_string (field , fc .FIELD_ATTR_NORMALIZE )
8792 if field_mode is not None :
8893 return field_mode
8994 if owner is not None :
90- owner_mode = _own_attr_string (owner , fc .FIELD_ATTR_NORMALIZE )
95+ owner_mode = _attr_string (owner , fc .FIELD_ATTR_NORMALIZE )
9196 if owner_mode is not None :
9297 return owner_mode
9398 return fc .NORMALIZE_DEFAULT
0 commit comments