metaobjects 1.0.11__tar.gz → 1.0.12__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (482) hide show
  1. {metaobjects-1.0.11 → metaobjects-1.0.12}/PKG-INFO +1 -1
  2. {metaobjects-1.0.11 → metaobjects-1.0.12}/pyproject.toml +1 -1
  3. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/cli.py +151 -0
  4. metaobjects-1.0.12/src/metaobjects/fmt.py +214 -0
  5. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/extract/__init__.py +2 -0
  6. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/extract/extract.py +34 -2
  7. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/extract/types.py +28 -1
  8. metaobjects-1.0.12/tests/codegen/test_cli_fmt.py +137 -0
  9. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_extractor_generator.py +41 -0
  10. metaobjects-1.0.12/tests/codegen/test_fmt_format_file.py +45 -0
  11. metaobjects-1.0.12/tests/conformance/test_fmt_conformance.py +54 -0
  12. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/extract/test_extract.py +100 -0
  13. {metaobjects-1.0.11 → metaobjects-1.0.12}/uv.lock +1 -1
  14. {metaobjects-1.0.11 → metaobjects-1.0.12}/.gitignore +0 -0
  15. {metaobjects-1.0.11 → metaobjects-1.0.12}/LICENSE +0 -0
  16. {metaobjects-1.0.11 → metaobjects-1.0.12}/README.md +0 -0
  17. {metaobjects-1.0.11 → metaobjects-1.0.12}/hatch_build.py +0 -0
  18. {metaobjects-1.0.11 → metaobjects-1.0.12}/scripts/generate_embedded_library.py +0 -0
  19. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/__init__.py +0 -0
  20. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/agent_context/__init__.py +0 -0
  21. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/agent_context/scaffold.py +0 -0
  22. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/apidocs/__init__.py +0 -0
  23. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/apidocs/api_model.py +0 -0
  24. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/apidocs/builder.py +0 -0
  25. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/apidocs/naming.py +0 -0
  26. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/apidocs/paths.py +0 -0
  27. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/apidocs/renderer.py +0 -0
  28. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/attr_class_map.py +0 -0
  29. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
  30. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/__init__.py +0 -0
  31. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/collision_names.py +0 -0
  32. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/config.py +0 -0
  33. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/constants.py +0 -0
  34. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/eject.py +0 -0
  35. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
  36. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
  37. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/format.py +0 -0
  38. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
  39. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generator.py +0 -0
  40. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generator_registry.py +0 -0
  41. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/__init__.py +0 -0
  42. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/entity_model.py +0 -0
  43. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
  44. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
  45. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/find_inbound.py +0 -0
  46. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
  47. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/m2m_codegen.py +0 -0
  48. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/names_generator.py +0 -0
  49. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
  50. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
  51. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
  52. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/router_generator.py +0 -0
  53. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/template_generator.py +0 -0
  54. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
  55. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
  56. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/instance_artifacts.py +0 -0
  57. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/metaobjects-config.schema.json +0 -0
  58. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/model_walk.py +0 -0
  59. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
  60. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/overwrite_policy.py +0 -0
  61. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/project_config.py +0 -0
  62. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/runner.py +0 -0
  63. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/runtime/__init__.py +0 -0
  64. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/runtime/constraint_errors.py +0 -0
  65. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
  66. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
  67. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
  68. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
  69. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
  70. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/type_map.py +0 -0
  71. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/codegen/value_objects.py +0 -0
  72. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/config/__init__.py +0 -0
  73. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/config/dependencies.py +0 -0
  74. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/config/neutral_config.py +0 -0
  75. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/config/source_resolver.py +0 -0
  76. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/core_types.py +0 -0
  77. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/datatype.py +0 -0
  78. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/documentation/__init__.py +0 -0
  79. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/documentation/doc_constants.py +0 -0
  80. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/documentation/doc_provider.py +0 -0
  81. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/documentation/doc_schema.py +0 -0
  82. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/errors.py +0 -0
  83. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/library/__init__.py +0 -0
  84. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/library/embedded_library.py +0 -0
  85. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/library/library_sources.py +0 -0
  86. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/loader/__init__.py +0 -0
  87. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/loader/merge.py +0 -0
  88. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/loader/meta_data_loader.py +0 -0
  89. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/loader/registered_validation.py +0 -0
  90. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/loader/sources/__init__.py +0 -0
  91. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/loader/sources/directory_source.py +0 -0
  92. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/loader/sources/file_source.py +0 -0
  93. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
  94. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/loader/sources/uri_source.py +0 -0
  95. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/loader/validate_discriminator.py +0 -0
  96. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/loader/validate_enum_normalize_ambiguity.py +0 -0
  97. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/loader/validate_field_mutability.py +0 -0
  98. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/loader/validate_source_escapes.py +0 -0
  99. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
  100. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
  101. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/loader/validation_passes.py +0 -0
  102. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/__init__.py +0 -0
  103. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/__init__.py +0 -0
  104. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/attr/__init__.py +0 -0
  105. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
  106. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
  107. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/field/__init__.py +0 -0
  108. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/field/field_constants.py +0 -0
  109. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/field/meta_field.py +0 -0
  110. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/identity/__init__.py +0 -0
  111. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
  112. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
  113. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/index/__init__.py +0 -0
  114. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/index/index_constants.py +0 -0
  115. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/index/meta_index.py +0 -0
  116. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/__init__.py +0 -0
  117. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/meta_object.py +0 -0
  118. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
  119. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
  120. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/object_constants.py +0 -0
  121. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/object_extract.py +0 -0
  122. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/value_object.py +0 -0
  123. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
  124. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
  125. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
  126. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
  127. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/relationship/relationship_references.py +0 -0
  128. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/requirement/__init__.py +0 -0
  129. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/requirement/meta_requirement.py +0 -0
  130. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/requirement/requirement_constants.py +0 -0
  131. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/validator/__init__.py +0 -0
  132. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
  133. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/meta_data.py +0 -0
  134. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/meta_root.py +0 -0
  135. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/__init__.py +0 -0
  136. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
  137. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
  138. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
  139. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
  140. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
  141. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
  142. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
  143. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
  144. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
  145. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/__init__.py +0 -0
  146. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
  147. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
  148. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
  149. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
  150. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
  151. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
  152. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
  153. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
  154. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/provider_extends.py +0 -0
  155. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/template/__init__.py +0 -0
  156. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/template/meta_template.py +0 -0
  157. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/template/prompt_provider.py +0 -0
  158. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta/template/template_constants.py +0 -0
  159. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/meta_endpoint.py +0 -0
  160. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/naming.py +0 -0
  161. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/naming_refs.py +0 -0
  162. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/parser.py +0 -0
  163. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/parser_yaml.py +0 -0
  164. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/provider.py +0 -0
  165. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/py.typed +0 -0
  166. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/registry.py +0 -0
  167. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/registry_manifest.py +0 -0
  168. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/__init__.py +0 -0
  169. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/email_document.py +0 -0
  170. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/escapers.py +0 -0
  171. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
  172. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/extract/coerce.py +0 -0
  173. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/extract/extract_map.py +0 -0
  174. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
  175. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/extract/locate.py +0 -0
  176. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/extract/normalize.py +0 -0
  177. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/extract/strip.py +0 -0
  178. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
  179. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/filesystem_provider.py +0 -0
  180. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/payload_accessors.py +0 -0
  181. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/prompt/__init__.py +0 -0
  182. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
  183. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
  184. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/prompt/prompt_field.py +0 -0
  185. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
  186. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/prompt/prompt_style.py +0 -0
  187. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/renderer.py +0 -0
  188. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/render/verify.py +0 -0
  189. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/runtime/__init__.py +0 -0
  190. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/runtime/llm_recorder.py +0 -0
  191. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/runtime/n2m_resolver.py +0 -0
  192. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/runtime/object_manager.py +0 -0
  193. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/runtime/tph.py +0 -0
  194. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/scope.py +0 -0
  195. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/serializer_json.py +0 -0
  196. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/shared/__init__.py +0 -0
  197. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/shared/base_types.py +0 -0
  198. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/shared/separators.py +0 -0
  199. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/shared/structural.py +0 -0
  200. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/source/__init__.py +0 -0
  201. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/source/error_source.py +0 -0
  202. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/source/json_path.py +0 -0
  203. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/source/semantic_diff.py +0 -0
  204. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/source/yaml_positions.py +0 -0
  205. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/source_resolution.py +0 -0
  206. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/__init__.py +0 -0
  207. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/attr.json +0 -0
  208. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/db.json +0 -0
  209. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/documentation.json +0 -0
  210. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/field.json +0 -0
  211. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/identity.json +0 -0
  212. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/index.json +0 -0
  213. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/layout.json +0 -0
  214. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/object.json +0 -0
  215. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/origin.json +0 -0
  216. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/prompt.json +0 -0
  217. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/relationship.json +0 -0
  218. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/requirement.json +0 -0
  219. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/source.json +0 -0
  220. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/template.json +0 -0
  221. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
  222. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/ui.json +0 -0
  223. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/validator.json +0 -0
  224. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/view.json +0 -0
  225. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/super_resolve.py +0 -0
  226. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/validation_types.py +0 -0
  227. {metaobjects-1.0.11 → metaobjects-1.0.12}/src/metaobjects/yaml_desugar.py +0 -0
  228. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/__init__.py +0 -0
  229. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/__init__.py +0 -0
  230. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/gen_suite.py +0 -0
  231. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
  232. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/golden/extends/expected/Program.py +0 -0
  233. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/golden/extends/meta.json +0 -0
  234. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
  235. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
  236. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/golden/nested-array/meta.json +0 -0
  237. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
  238. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/golden/scalars/expected/Report.py +0 -0
  239. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/golden/scalars/meta.json +0 -0
  240. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
  241. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/golden/vanilla/meta.json +0 -0
  242. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_abstract_conformance.py +0 -0
  243. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_api_docs_builder.py +0 -0
  244. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_api_docs_paths.py +0 -0
  245. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_cli.py +0 -0
  246. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_cli_config_gen.py +0 -0
  247. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_cli_config_verify.py +0 -0
  248. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_cli_dependencies.py +0 -0
  249. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_cli_gen_unknown_attr.py +0 -0
  250. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_cli_providers.py +0 -0
  251. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_cli_registry.py +0 -0
  252. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_cli_render_helper_template_root.py +0 -0
  253. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_cli_staleness_nudge.py +0 -0
  254. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_cli_verify_strict.py +0 -0
  255. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_cli_verify_subverbs.py +0 -0
  256. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_codegen_compile_conformance.py +0 -0
  257. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_constants_config.py +0 -0
  258. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_eject.py +0 -0
  259. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_eject_runtime.py +0 -0
  260. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_entity_model.py +0 -0
  261. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_enum_conformance.py +0 -0
  262. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
  263. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_extract_tier_collision.py +0 -0
  264. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_filter_allowlist_generator.py +0 -0
  265. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_format.py +0 -0
  266. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
  267. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_fr010_output_codegen.py +0 -0
  268. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
  269. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_gen_state_keying.py +0 -0
  270. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_generator.py +0 -0
  271. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_generator_extension_seams.py +0 -0
  272. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_golden.py +0 -0
  273. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
  274. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_inheritance_conformance.py +0 -0
  275. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_instance_artifacts.py +0 -0
  276. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_m2m_codegen.py +0 -0
  277. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_names_extends_chain.py +0 -0
  278. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_names_generator.py +0 -0
  279. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_no_magic_physical_names.py +0 -0
  280. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_origin_nullability.py +0 -0
  281. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_output_parser_generator.py +0 -0
  282. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_overwrite_policy.py +0 -0
  283. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_overwrite_policy_hash.py +0 -0
  284. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_project_config.py +0 -0
  285. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_projection_compile.py +0 -0
  286. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_recipe_generators.py +0 -0
  287. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_render_helper_conformance.py +0 -0
  288. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_render_helper_generator.py +0 -0
  289. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_reverse_finders.py +0 -0
  290. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_route_path_naming.py +0 -0
  291. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_router_autoset.py +0 -0
  292. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_router_generator.py +0 -0
  293. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_router_generator_m2m_target_tph.py +0 -0
  294. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_router_generator_tph_m2m.py +0 -0
  295. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_router_generator_tph_m2m_shadowed.py +0 -0
  296. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_runner.py +0 -0
  297. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_source_resolution.py +0 -0
  298. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_sourceless_entity_surface.py +0 -0
  299. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_sourceless_projection.py +0 -0
  300. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_template_data.py +0 -0
  301. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_template_generator.py +0 -0
  302. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_template_output_pattern.py +0 -0
  303. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_template_scope_helpers.py +0 -0
  304. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_template_scope_walk.py +0 -0
  305. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_template_spec.py +0 -0
  306. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_tph_codegen.py +0 -0
  307. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_trace_helper_generator.py +0 -0
  308. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_type_map.py +0 -0
  309. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_validation_conformance.py +0 -0
  310. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_value_objects.py +0 -0
  311. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/codegen/test_write_through.py +0 -0
  312. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/config/__init__.py +0 -0
  313. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/config/test_dependencies.py +0 -0
  314. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/config/test_library_package_guard.py +0 -0
  315. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/config/test_neutral_config.py +0 -0
  316. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/config/test_source_resolver.py +0 -0
  317. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/__init__.py +0 -0
  318. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/capabilities.py +0 -0
  319. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/conformance-expected-failures.json +0 -0
  320. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/conformance_adapter.py +0 -0
  321. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/corpus.py +0 -0
  322. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/expected_failures.py +0 -0
  323. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/fixture_discovery.py +0 -0
  324. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/navigator.py +0 -0
  325. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
  326. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_conformance.py +0 -0
  327. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_dependency_conformance.py +0 -0
  328. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_extract_conformance.py +0 -0
  329. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_extract_object_array_bounds.py +0 -0
  330. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_extract_object_verdict.py +0 -0
  331. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_fr010_loader_attrs.py +0 -0
  332. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_fr011_attrs.py +0 -0
  333. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_generator_registry_conformance.py +0 -0
  334. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_object_model_conformance.py +0 -0
  335. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_provider_composition_conformance.py +0 -0
  336. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_registry_conformance.py +0 -0
  337. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_runner_hardfail.py +0 -0
  338. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_scope_conformance.py +0 -0
  339. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_source_resolution_conformance.py +0 -0
  340. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_spec_metamodel_embed.py +0 -0
  341. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_strict_attr_load.py +0 -0
  342. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_template_codegen_conformance.py +0 -0
  343. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_template_generator_conformance.py +0 -0
  344. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/test_yaml_conformance.py +0 -0
  345. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
  346. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/__init__.py +0 -0
  347. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/api_contract_assertions.py +0 -0
  348. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/api_contract_jsonb_server.py +0 -0
  349. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/api_contract_m2m_server.py +0 -0
  350. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/api_contract_server.py +0 -0
  351. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/generated_jsonb_app.py +0 -0
  352. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/generated_m2m_app.py +0 -0
  353. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/generated_projection_app.py +0 -0
  354. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/generated_router_app.py +0 -0
  355. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/generated_tph_app.py +0 -0
  356. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/meta_ai_trace.yaml +0 -0
  357. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/normalization.py +0 -0
  358. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/postgres_container.py +0 -0
  359. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/query_runner.py +0 -0
  360. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/scenarios.py +0 -0
  361. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/test_api_contract.py +0 -0
  362. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/test_api_contract_generated.py +0 -0
  363. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/test_api_contract_jsonb.py +0 -0
  364. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/test_api_contract_m2m.py +0 -0
  365. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/test_api_contract_m2m_generated.py +0 -0
  366. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/test_api_contract_projection.py +0 -0
  367. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/test_api_contract_tph_generated.py +0 -0
  368. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/test_generated_router_uuid_pk.py +0 -0
  369. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/test_llm_call_trace.py +0 -0
  370. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/test_m2m_target_tph_generated.py +0 -0
  371. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/test_normalization.py +0 -0
  372. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/test_query_scenarios.py +0 -0
  373. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/test_runtime_return_types.py +0 -0
  374. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/test_tph_m2m_generated.py +0 -0
  375. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/integration/test_tph_m2m_shadowed_generated.py +0 -0
  376. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/loader/__init__.py +0 -0
  377. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/loader/test_abstract_subtype_authored.py +0 -0
  378. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/loader/test_child_wrapper_body_shape.py +0 -0
  379. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/loader/test_enum_extends_values_conflict.py +0 -0
  380. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/loader/test_field_mutability_order.py +0 -0
  381. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/loader/test_shipped_library_ai.py +0 -0
  382. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/loader/test_template_payload_target_210.py +0 -0
  383. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/open_closed_proof_test.py +0 -0
  384. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/__init__.py +0 -0
  385. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/extract/__init__.py +0 -0
  386. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/extract/test_coerce.py +0 -0
  387. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/extract/test_extract_map.py +0 -0
  388. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/extract/test_json_forgiving_reader.py +0 -0
  389. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/extract/test_locate.py +0 -0
  390. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/extract/test_model.py +0 -0
  391. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/extract/test_normalize.py +0 -0
  392. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/extract/test_strip.py +0 -0
  393. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
  394. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/prompt/__init__.py +0 -0
  395. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/prompt/test_output_format_renderer.py +0 -0
  396. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/test_email_document.py +0 -0
  397. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/test_filesystem_provider.py +0 -0
  398. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/test_output_format_renderer_nested.py +0 -0
  399. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/test_output_prompt_conformance.py +0 -0
  400. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/test_render_conformance.py +0 -0
  401. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/test_render_max_chars.py +0 -0
  402. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/test_render_model_payload.py +0 -0
  403. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/test_verify.py +0 -0
  404. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/render/test_verify_conformance.py +0 -0
  405. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/runtime/test_constraint_errors.py +0 -0
  406. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/runtime/test_object_manager_currency_read.py +0 -0
  407. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/runtime/test_object_manager_enum_intvaluemap.py +0 -0
  408. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/runtime/test_object_manager_table_name.py +0 -0
  409. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/source/__init__.py +0 -0
  410. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/source/test_fr5c_merge_attribution.py +0 -0
  411. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/source/test_fr5d_reference_resolution.py +0 -0
  412. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/source/test_fr5e_database_source_shape.py +0 -0
  413. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/source/test_json_path.py +0 -0
  414. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/source/test_semantic_diff.py +0 -0
  415. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/source/test_source_on_node.py +0 -0
  416. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/source/test_yaml_positions.py +0 -0
  417. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/test_api_docs_accuracy.py +0 -0
  418. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/test_meta_endpoint.py +0 -0
  419. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/__init__.py +0 -0
  420. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_agent_context_staleness.py +0 -0
  421. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_capabilities.py +0 -0
  422. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_column_naming_strategy.py +0 -0
  423. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_common_attrs.py +0 -0
  424. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_core_types.py +0 -0
  425. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_derive_m2m_declaring_entity.py +0 -0
  426. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_effective_children_sibling_shadowing.py +0 -0
  427. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_effective_package.py +0 -0
  428. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_errors.py +0 -0
  429. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_field_enum.py +0 -0
  430. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_field_enum_intvaluemap.py +0 -0
  431. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_field_map_validation.py +0 -0
  432. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
  433. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_file_source_id.py +0 -0
  434. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
  435. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_index_lookup.py +0 -0
  436. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_llm_recorder.py +0 -0
  437. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_loader.py +0 -0
  438. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_loader_bom.py +0 -0
  439. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_loader_class.py +0 -0
  440. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_merge.py +0 -0
  441. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_meta_attr.py +0 -0
  442. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_meta_data.py +0 -0
  443. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_meta_source.py +0 -0
  444. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_module_shortcuts.py +0 -0
  445. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_n2m_resolver.py +0 -0
  446. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_n2m_resolver_inherited.py +0 -0
  447. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_no_dead_config_fields.py +0 -0
  448. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
  449. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
  450. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_object_manager_write_through.py +0 -0
  451. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_one_primary_source.py +0 -0
  452. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_parser.py +0 -0
  453. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_parser_yaml.py +0 -0
  454. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_provider.py +0 -0
  455. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_provider_extension.py +0 -0
  456. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_registry.py +0 -0
  457. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_registry_completeness.py +0 -0
  458. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_registry_extend.py +0 -0
  459. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_registry_sealed.py +0 -0
  460. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_relationship_m2m_validation.py +0 -0
  461. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_relationship_references.py +0 -0
  462. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_relationship_referential_actions.py +0 -0
  463. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_resolution_key.py +0 -0
  464. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
  465. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_serializer.py +0 -0
  466. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_serializer_shared_document.py +0 -0
  467. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_shared_constants.py +0 -0
  468. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_smoke.py +0 -0
  469. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_source_escapes.py +0 -0
  470. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_sources.py +0 -0
  471. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_strict_child_placement.py +0 -0
  472. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_super_resolve.py +0 -0
  473. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_template_toolcall.py +0 -0
  474. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
  475. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_validation_attr_schema.py +0 -0
  476. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_validation_filter_values.py +0 -0
  477. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_validation_origin_195.py +0 -0
  478. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_validation_origin_paths.py +0 -0
  479. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_validation_sort_field.py +0 -0
  480. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_validation_warnings.py +0 -0
  481. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_write_coercion_arrays.py +0 -0
  482. {metaobjects-1.0.11 → metaobjects-1.0.12}/tests/unit/test_yaml_desugar.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: metaobjects
3
- Version: 1.0.11
3
+ Version: 1.0.12
4
4
  Summary: Cross-language metadata standard: declare typed entities once, generate idiomatic drift-checked code across languages — Python port.
5
5
  Project-URL: Homepage, https://metaobjects.dev
6
6
  Project-URL: Repository, https://github.com/metaobjectsdev/metaobjects
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "metaobjects"
3
- version = "1.0.11"
3
+ version = "1.0.12"
4
4
  description = "Cross-language metadata standard: declare typed entities once, generate idiomatic drift-checked code across languages — Python port."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -1069,6 +1069,132 @@ def _cmd_list(_args: argparse.Namespace) -> int:
1069
1069
  return 0
1070
1070
 
1071
1071
 
1072
+ def _describe_fmt_report(report: "object", cwd: Path) -> str:
1073
+ from metaobjects import fmt
1074
+
1075
+ try:
1076
+ rel = report.path.relative_to(cwd)
1077
+ except ValueError:
1078
+ rel = report.path
1079
+ if report.status == fmt.STATUS_FORMATTED:
1080
+ return f" reformatted {rel}"
1081
+ if report.status == fmt.STATUS_WOULD_FORMAT:
1082
+ return f" not canonical {rel}"
1083
+ if report.status == fmt.STATUS_UNCHANGED:
1084
+ return f" ok {rel}"
1085
+ if report.status == fmt.STATUS_SKIPPED_YAML:
1086
+ return f" skipped (yaml) {rel} — {report.detail}"
1087
+ if report.status == fmt.STATUS_SKIPPED_OVERLAY:
1088
+ return (
1089
+ f" skipped (overlay) {rel} — this file declares an overlay fmt "
1090
+ "cannot resolve standalone"
1091
+ )
1092
+ if report.status == fmt.STATUS_ERROR:
1093
+ return f" error {rel} — {report.detail}"
1094
+ return f" {report.status} {rel}" # pragma: no cover — exhaustive in practice
1095
+
1096
+
1097
+ def _cmd_fmt(args: argparse.Namespace) -> int:
1098
+ """``fmt`` (#304) — rewrite metadata files into canonical form; ``--check``
1099
+ lists non-canonical files and exits non-zero without changing anything.
1100
+
1101
+ Mirrors the TS reference surface exactly: no ``metadata_dir`` positional —
1102
+ files come from the neutral ``.metaobjects/config.json`` ladder
1103
+ (:func:`resolve_metadata_location`, rungs 3-4; this command does not read
1104
+ this port's own ``metaobjects.config.yaml`` rung 2, matching the scope the
1105
+ C# and Java ports also keep for `fmt`), optionally narrowed by explicit
1106
+ file arguments.
1107
+ """
1108
+ from metaobjects import fmt
1109
+ from metaobjects.core_types import core_providers
1110
+ from metaobjects.library import library_sources
1111
+ from metaobjects.provider import compose_registry
1112
+
1113
+ providers_extra, providers_ok = _providers_from_args(args)
1114
+ if not providers_ok:
1115
+ return 1
1116
+ providers = [*core_providers, *providers_extra]
1117
+ registry = compose_registry(providers)
1118
+
1119
+ cwd = Path.cwd()
1120
+ collection = _resolve_metadata_location_or_print_error(None, cwd)
1121
+ if collection is None:
1122
+ return 1
1123
+
1124
+ all_files = list(collection.files)
1125
+ own_files = list(collection.own_files)
1126
+
1127
+ if args.files:
1128
+ wanted = [Path(f).resolve() for f in args.files]
1129
+ owned_set = {p.resolve() for p in own_files}
1130
+ missing = [str(p) for p in wanted if p not in owned_set]
1131
+ if missing:
1132
+ print(
1133
+ "error: not among this project's resolved metadata sources: "
1134
+ + ", ".join(missing),
1135
+ file=sys.stderr,
1136
+ )
1137
+ print(
1138
+ "metaobjects fmt only formats files the metadata-location ladder "
1139
+ "already resolves — pass no arguments to format every one of them.",
1140
+ file=sys.stderr,
1141
+ )
1142
+ return 1
1143
+ wanted_set = {p for p in wanted}
1144
+ targets = [p for p in own_files if p.resolve() in wanted_set]
1145
+ else:
1146
+ targets = own_files
1147
+
1148
+ lib_sources = library_sources(list(collection.libraries)) if collection.libraries else []
1149
+
1150
+ result = fmt.run(
1151
+ all_files=all_files,
1152
+ target_files=targets,
1153
+ file_ids=dict(collection.file_ids),
1154
+ registry=registry,
1155
+ lib_sources=lib_sources,
1156
+ check=bool(args.check),
1157
+ providers=providers,
1158
+ )
1159
+
1160
+ if result.fatal is not None:
1161
+ print(f"error: {result.fatal}", file=sys.stderr)
1162
+ return 1
1163
+
1164
+ if not result.files:
1165
+ print("metaobjects fmt — no metadata files to format.")
1166
+ return 0
1167
+
1168
+ for report in result.files:
1169
+ print(_describe_fmt_report(report, cwd))
1170
+
1171
+ errored = sum(1 for r in result.files if r.status == fmt.STATUS_ERROR)
1172
+ needs_format = sum(1 for r in result.files if r.status == fmt.STATUS_WOULD_FORMAT)
1173
+ reformatted = sum(1 for r in result.files if r.status == fmt.STATUS_FORMATTED)
1174
+
1175
+ if args.check:
1176
+ if needs_format or errored:
1177
+ suffix = f", {errored} error(s)" if errored else ""
1178
+ print(
1179
+ f"metaobjects fmt --check — {needs_format} file(s) not canonical{suffix}. "
1180
+ "Run `metaobjects fmt` to fix.",
1181
+ file=sys.stderr,
1182
+ )
1183
+ return 1
1184
+ print("metaobjects fmt --check — every file is already canonical.")
1185
+ return 0
1186
+
1187
+ if errored:
1188
+ print(
1189
+ f"metaobjects fmt — {errored} file(s) could not be formatted safely (left unchanged).",
1190
+ file=sys.stderr,
1191
+ )
1192
+ return 1
1193
+
1194
+ print(f"metaobjects fmt — {reformatted} file(s) reformatted.")
1195
+ return 0
1196
+
1197
+
1072
1198
  def _cmd_eject(args: argparse.Namespace) -> int:
1073
1199
  """Copy reference generators into ``codegen/generators/`` to own (ADR-0034 Am. 3)."""
1074
1200
  root = Path(args.root) if args.root else Path.cwd()
@@ -2493,6 +2619,31 @@ def _build_parser() -> argparse.ArgumentParser:
2493
2619
  )
2494
2620
  verify.set_defaults(func=_cmd_verify)
2495
2621
 
2622
+ fmt_p = sub.add_parser(
2623
+ "fmt",
2624
+ help="rewrite metadata files into canonical form (#304)",
2625
+ )
2626
+ fmt_p.add_argument(
2627
+ "files",
2628
+ nargs="*",
2629
+ metavar="FILE",
2630
+ help="optional explicit file(s) to format — must be members of this "
2631
+ "project's resolved metadata sources; omit to format every one of them",
2632
+ )
2633
+ fmt_p.add_argument(
2634
+ "--check",
2635
+ action="store_true",
2636
+ help="list files that are not canonical and exit non-zero; changes nothing",
2637
+ )
2638
+ fmt_p.add_argument(
2639
+ "--provider",
2640
+ action="append",
2641
+ default=None,
2642
+ metavar="MODULE:SYMBOL",
2643
+ help="consumer-registered Provider(s), repeatable (module:symbol)",
2644
+ )
2645
+ fmt_p.set_defaults(func=_cmd_fmt)
2646
+
2496
2647
  eject_p = sub.add_parser(
2497
2648
  "eject",
2498
2649
  help="copy reference generators into codegen/generators/ to own and edit",
@@ -0,0 +1,214 @@
1
+ """``metaobjects fmt`` (#304) — rewrite metadata files into the canonical form
2
+ the cross-port canonical serializer already produces. ``--check`` lists files
3
+ that are not canonical and exits non-zero without changing anything.
4
+
5
+ Mirrors the TS reference (``packages/metadata/src/fmt.ts`` +
6
+ ``packages/cli/src/lib/fmt-engine.ts``) and the C#/Java ports exactly:
7
+
8
+ - Each file is formatted STANDALONE — own-mode, declared-here layer only
9
+ (ADR-0039). ``parse_document`` already builds a fresh, unmerged tree per
10
+ document (this port's loader does parse -> merge -> super-resolve as three
11
+ separate steps, unlike TS/C#'s accumulating-root parser) — calling it
12
+ directly and never running ``merge_roots``/``resolve_supers`` is what makes
13
+ a cross-file ``extends`` round-trip untouched (the raw ``super_ref`` string
14
+ is read directly by ``canonical_serialize``, never its resolution) and an
15
+ ``overlay: true`` node never even attempt a merge.
16
+ - An ``overlay: true`` node is tagged (``is_overlay``) by the parser but never
17
+ resolved here — Python's overlay MERGE only happens in ``loader/merge.py``,
18
+ which this module never calls. A file containing one anywhere in its tree
19
+ (detected by :func:`_contains_overlay`) is reported as a skip rather than
20
+ guessed at — the concrete shape of "overlay files stay overlays".
21
+ - YAML is always skipped: no canonical YAML emitter exists (ADR-0006).
22
+ - Before writing, the whole project is reloaded with the candidate
23
+ substituted in via an in-memory source (never touching disk until proven
24
+ safe) and the write is refused unless that reload has no errors AND its
25
+ canonical form is byte-identical to the untouched baseline.
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import json
31
+ from dataclasses import dataclass, field
32
+ from pathlib import Path
33
+ from typing import Callable
34
+
35
+ from metaobjects.errors import MetaError
36
+ from metaobjects.loader.meta_data_loader import MetaDataLoader
37
+ from metaobjects.loader.sources.file_source import FileSource
38
+ from metaobjects.loader.sources.meta_data_source import InMemoryStringSource, MetaDataSource
39
+ from metaobjects.meta.meta_data import MetaData
40
+ from metaobjects.parser import parse_document
41
+ from metaobjects.registry import TypeRegistry
42
+ from metaobjects.serializer_json import canonical_serialize
43
+
44
+ #: Statuses a single file's run can report.
45
+ STATUS_FORMATTED = "formatted"
46
+ STATUS_WOULD_FORMAT = "would-format"
47
+ STATUS_UNCHANGED = "unchanged"
48
+ STATUS_SKIPPED_YAML = "skipped-yaml"
49
+ STATUS_SKIPPED_OVERLAY = "skipped-overlay"
50
+ STATUS_ERROR = "error"
51
+
52
+
53
+ @dataclass
54
+ class FormatFileResult:
55
+ ok: bool
56
+ overlay: bool = False
57
+ text: str | None = None
58
+ message: str | None = None
59
+
60
+
61
+ def _contains_overlay(node: MetaData) -> bool:
62
+ """Whether *node* or any descendant (own children only — this tree was
63
+ never merged, so every child already is its own) carries ``overlay: true``.
64
+ """
65
+ if getattr(node, "is_overlay", False):
66
+ return True
67
+ return any(_contains_overlay(child) for child in node.own_children())
68
+
69
+
70
+ def format_file(content: str, registry: TypeRegistry, source_id: str) -> FormatFileResult:
71
+ """Format one file's own content. Parses *content* standalone via
72
+ :func:`parse_document` — never merged with any other file, super
73
+ resolution never run — and, on a clean parse with no overlay anywhere in
74
+ the tree, returns the canonical serialization of the resulting file root.
75
+ Never raises for a malformed file; that comes back as ``ok=False``.
76
+ """
77
+ # Strip a UTF-8 BOM before parsing — json.loads rejects one outright
78
+ # ("Unexpected UTF-8 BOM (decode using utf-8-sig)"), and Java-authored
79
+ # files often carry one.
80
+ normalized = content[1:] if content.startswith("") else content
81
+ try:
82
+ doc = json.loads(normalized)
83
+ except json.JSONDecodeError as exc:
84
+ return FormatFileResult(ok=False, message=f"invalid JSON: {exc}")
85
+
86
+ try:
87
+ result = parse_document(doc, registry, source_id)
88
+ except Exception as exc: # a few structural failures raise rather than record
89
+ return FormatFileResult(ok=False, message=str(exc))
90
+
91
+ if result.errors:
92
+ message = "; ".join(e.message for e in result.errors)
93
+ return FormatFileResult(ok=False, message=message)
94
+
95
+ if _contains_overlay(result.root):
96
+ return FormatFileResult(
97
+ ok=False,
98
+ overlay=True,
99
+ message="this file declares an overlay fmt cannot resolve standalone",
100
+ )
101
+
102
+ return FormatFileResult(ok=True, text=canonical_serialize(result.root))
103
+
104
+
105
+ @dataclass
106
+ class FileReport:
107
+ path: Path
108
+ status: str
109
+ detail: str | None = None
110
+
111
+
112
+ @dataclass
113
+ class RunResult:
114
+ files: list[FileReport] = field(default_factory=list)
115
+ fatal: str | None = None
116
+
117
+
118
+ def run(
119
+ all_files: list[Path],
120
+ target_files: list[Path],
121
+ file_ids: dict[Path, str],
122
+ registry: TypeRegistry,
123
+ lib_sources: list[MetaDataSource],
124
+ check: bool,
125
+ providers: list[object] | None = None,
126
+ ) -> RunResult:
127
+ """Run fmt over *target_files* (a subset of *all_files* — the project's
128
+ FULL resolved file set, needed for the whole-project safety-check reload
129
+ regardless of which files are in scope to format).
130
+
131
+ *providers* must be the SAME provider list *registry* (used for every
132
+ standalone per-file parse) was composed from — the whole-project baseline
133
+ and safety-check reloads build their own `MetaDataLoader`, which recomposes
134
+ a registry from *providers* itself rather than taking `registry` directly,
135
+ so passing a different set here would silently check two vocabularies
136
+ against each other.
137
+ """
138
+
139
+ def source_id(path: Path) -> str:
140
+ return file_ids.get(path) or path.name
141
+
142
+ def build_sources(
143
+ override_path: Path | None = None, override_text: str | None = None
144
+ ) -> list[MetaDataSource]:
145
+ sources: list[MetaDataSource] = list(lib_sources)
146
+ for p in all_files:
147
+ if override_path is not None and p == override_path:
148
+ sources.append(InMemoryStringSource(override_text or "", id=source_id(p)))
149
+ else:
150
+ sources.append(FileSource(p, id=source_id(p)))
151
+ return sources
152
+
153
+ baseline = MetaDataLoader(providers=providers, strict=False).load(build_sources())
154
+ if baseline.errors:
155
+ detail = "\n".join(f" {e.code}: {e.message}" for e in baseline.errors)
156
+ return RunResult(
157
+ fatal=(
158
+ "this project's metadata does not currently load cleanly — fix the "
159
+ f"error(s) below, then re-run fmt:\n{detail}"
160
+ )
161
+ )
162
+ baseline_canonical = canonical_serialize(baseline.root)
163
+
164
+ reports: list[FileReport] = []
165
+ for path in target_files:
166
+ ext = path.suffix.lower()
167
+ if ext in (".yaml", ".yml"):
168
+ reports.append(
169
+ FileReport(
170
+ path,
171
+ STATUS_SKIPPED_YAML,
172
+ "no canonical YAML emitter exists (ADR-0006: JSON is the canonical "
173
+ "interchange form) — left untouched",
174
+ )
175
+ )
176
+ continue
177
+
178
+ content = path.read_text(encoding="utf-8")
179
+ formatted = format_file(content, registry, source_id(path))
180
+ if not formatted.ok:
181
+ reports.append(
182
+ FileReport(
183
+ path,
184
+ STATUS_SKIPPED_OVERLAY if formatted.overlay else STATUS_ERROR,
185
+ formatted.message,
186
+ )
187
+ )
188
+ continue
189
+
190
+ if formatted.text == content:
191
+ reports.append(FileReport(path, STATUS_UNCHANGED))
192
+ continue
193
+
194
+ test_load = MetaDataLoader(providers=providers, strict=False).load(
195
+ build_sources(path, formatted.text)
196
+ )
197
+ safe = not test_load.errors and canonical_serialize(test_load.root) == baseline_canonical
198
+ if not safe:
199
+ reports.append(
200
+ FileReport(
201
+ path,
202
+ STATUS_ERROR,
203
+ "formatting this file would change the loaded model's meaning — left unchanged",
204
+ )
205
+ )
206
+ continue
207
+
208
+ if check:
209
+ reports.append(FileReport(path, STATUS_WOULD_FORMAT))
210
+ else:
211
+ path.write_text(formatted.text, encoding="utf-8")
212
+ reports.append(FileReport(path, STATUS_FORMATTED))
213
+
214
+ return RunResult(files=reports)
@@ -25,6 +25,7 @@ from metaobjects.render.extract.types import (
25
25
  Format,
26
26
  Normalizer,
27
27
  OnField,
28
+ OnLocate,
28
29
  ExtractOptions,
29
30
  ExtractionOutcome,
30
31
  ExtractSchema,
@@ -45,6 +46,7 @@ __all__ = [
45
46
  "JsonForgivingReader",
46
47
  "Normalizer",
47
48
  "OnField",
49
+ "OnLocate",
48
50
  "ExtractOptions",
49
51
  "ExtractionOutcome",
50
52
  "ExtractSchema",
@@ -38,23 +38,55 @@ def extract(
38
38
  stripped = _strip.strip(text)
39
39
  ci = o.tolerance != Tolerance.STRICT
40
40
 
41
+ # FR-364: the document-level on_locate hook runs BEFORE the default locator. A non-None
42
+ # return is the payload span, fed into the same format-specific forgiving reader a
43
+ # default-located span would be — tolerance/coercion/normalizers/on_field downstream are
44
+ # unaffected. A None return (or no hook) falls through to the default locate strategy
45
+ # unchanged. A raised exception propagates (not swallowed), matching on_field.
46
+ located: str | None = None if o.on_locate is None else o.on_locate(text if text is not None else "", schema.format)
47
+
41
48
  # XML rootless (opts.rootless): the payload's fields ARE the top-level elements — there
42
49
  # is no enclosing root to locate — so parse the whole stripped text's top-level elements
43
50
  # directly. Otherwise locate the <rootName> span as before. JSON is unaffected. Mirrors
44
51
  # Java Extract.extract.
45
52
  span: str | None
46
53
  raw: dict[str, object]
47
- if schema.format == Format.JSON:
54
+ # Whether the SELECTED region (not the original reply) was itself empty/blank — the signal
55
+ # mark_empty() keys on below. For the default path this is the pre-existing "nothing to
56
+ # parse" test (stripped == "" or span is None); for on_locate it must be judged against the
57
+ # hook's OWN return, not the original text — otherwise an empty located span (e.g. the hook
58
+ # deliberately returning "") reports "not empty" while every field is LOST, because the
59
+ # original reply was non-blank even though the thing on_locate chose to parse was.
60
+ region_blank: bool
61
+ if located is not None:
62
+ span = located
63
+ if schema.format == Format.JSON:
64
+ raw = JsonForgivingReader().read(located)
65
+ elif o.rootless:
66
+ raw = XmlForgivingReader().read_rootless(located, ci)
67
+ else:
68
+ raw = XmlForgivingReader().read(located, ci)
69
+ # `from_` is deliberately left empty rather than the original text: a document-level
70
+ # audit entry that copied the whole raw reply (which can be arbitrarily large) into the
71
+ # report on every call would make the report itself heavy for no benefit `to`'s length
72
+ # doesn't already give. `to` is the located span's LENGTH, not the span text, for the
73
+ # same reason.
74
+ report.add_coercion(Coercion("", "", str(len(located)), "onLocate"))
75
+ region_blank = located.strip() == ""
76
+ elif schema.format == Format.JSON:
48
77
  span = _select_json(text, stripped, schema.fields, ci)
49
78
  raw = {} if span is None else JsonForgivingReader().read(span)
79
+ region_blank = stripped == "" or span is None
50
80
  elif o.rootless:
51
81
  span = None if stripped == "" else stripped
52
82
  raw = {} if span is None else XmlForgivingReader().read_rootless(stripped, ci)
83
+ region_blank = stripped == "" or span is None
53
84
  else:
54
85
  span = _locate.xml(stripped, schema.root_name, ci)
55
86
  raw = {} if span is None else XmlForgivingReader().read(span, ci)
87
+ region_blank = stripped == "" or span is None
56
88
 
57
- if not raw and (stripped == "" or span is None):
89
+ if not raw and region_blank:
58
90
  report.mark_empty()
59
91
 
60
92
  _extract(schema.fields, raw, "", data, report, o, ci)
@@ -27,6 +27,17 @@ T = TypeVar("T")
27
27
  OnField = Callable[[str, str, "FieldSpec"], object | None]
28
28
  Normalizer = Callable[[str], object | None]
29
29
 
30
+ # FR-364: the document-level locate hook: (text, format) -> payload substring | None.
31
+ # Receives the RAW reply text (never None; an absent document is normalized to ``""``
32
+ # before the hook runs) and the schema's declared ``Format``. Returning ``None`` falls
33
+ # back to the default locator (the fenced-then-first-object rule #363 fixed). A non-None
34
+ # return is parsed by the normal pipeline exactly like a default-located span —
35
+ # tolerance, coercion, ``normalizers``, and ``on_field`` downstream are unaffected — so
36
+ # this hook only decides WHICH text is the payload, never how it is parsed. The returned
37
+ # text need not be a literal substring of the input (the hook may synthesize it). A
38
+ # raised exception propagates (it is not swallowed), matching ``on_field``.
39
+ OnLocate = Callable[[str, "Format"], "str | None"]
40
+
30
41
 
31
42
  class Format(Enum):
32
43
  """Document format the extract pipeline targets."""
@@ -248,7 +259,8 @@ class ExtractOptions:
248
259
  """Bounded runtime override surface (the "20%").
249
260
 
250
261
  ``aliases``/``normalizers`` are MERGED with the schema's, runtime winning on key
251
- conflict. ``on_field`` is the single bespoke-coercion hook.
262
+ conflict. ``on_field`` is the single per-field bespoke-coercion hook; ``on_locate``
263
+ is the single document-level (payload-location) hook.
252
264
 
253
265
  ``rootless`` (XML only): when ``True``, the input has NO enclosing root element —
254
266
  the payload's fields ARE the top-level elements (a flat sequence like
@@ -259,6 +271,7 @@ class ExtractOptions:
259
271
  aliases: dict[str, str] = field(default_factory=dict)
260
272
  normalizers: dict[str, Normalizer] = field(default_factory=dict)
261
273
  on_field: OnField | None = None
274
+ on_locate: OnLocate | None = None
262
275
  rootless: bool = False
263
276
 
264
277
  @staticmethod
@@ -271,6 +284,19 @@ class ExtractOptions:
271
284
  aliases=dict(self.aliases),
272
285
  normalizers=dict(self.normalizers),
273
286
  on_field=self.on_field,
287
+ on_locate=self.on_locate,
288
+ rootless=self.rootless,
289
+ )
290
+
291
+ def with_on_locate(self, hook: OnLocate | None) -> "ExtractOptions":
292
+ """The single document-level locate hook. See ``OnLocate``. Returns a copy
293
+ with ``on_locate`` set."""
294
+ return ExtractOptions(
295
+ tolerance=self.tolerance,
296
+ aliases=dict(self.aliases),
297
+ normalizers=dict(self.normalizers),
298
+ on_field=self.on_field,
299
+ on_locate=hook,
274
300
  rootless=self.rootless,
275
301
  )
276
302
 
@@ -282,6 +308,7 @@ class ExtractOptions:
282
308
  aliases=dict(self.aliases),
283
309
  normalizers=dict(self.normalizers),
284
310
  on_field=self.on_field,
311
+ on_locate=self.on_locate,
285
312
  rootless=r,
286
313
  )
287
314
 
@@ -0,0 +1,137 @@
1
+ """`metaobjects fmt` (#304) — rewrite metadata files into canonical form.
2
+
3
+ Mirrors the TS reference's integration test and the C#/Java ports' Mojo/CLI
4
+ tests: a messy file reformats, an already-canonical file is untouched, an
5
+ overlay file with no local base is skipped, and a YAML file is always
6
+ skipped. No `metadata_dir` positional — matches the TS reference surface:
7
+ files come from the neutral `.metaobjects/config.json` ladder (here, just
8
+ the default `metaobjects/` directory, since no project in these tests
9
+ declares a config), optionally narrowed by explicit file arguments.
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import json
14
+ from pathlib import Path
15
+
16
+ import pytest
17
+
18
+ from metaobjects.cli import main
19
+
20
+ MESSY_WIDGET = """\
21
+ { "metadata.root": { "package": "acme", "children": [
22
+ { "object.entity": { "@description": "A widget", "name": "Widget", "children": [
23
+ { "field.string": { "name": "sku", "@maxLength": 40, "@required": true } }
24
+ ]}}
25
+ ]}}
26
+ """
27
+
28
+ CANONICAL_GADGET = (
29
+ "{\n \"metadata.root\": {\n \"package\": \"acme\",\n \"children\": [\n"
30
+ " {\n \"object.entity\": {\n \"name\": \"Gadget\",\n"
31
+ " \"children\": [\n {\n \"field.string\": {\n"
32
+ " \"name\": \"label\"\n }\n }\n ]\n"
33
+ " }\n }\n ]\n }\n}\n"
34
+ )
35
+
36
+ OVERLAY_WIDGET_UI = """\
37
+ { "metadata.root": { "package": "acme", "children": [
38
+ { "object.entity": { "name": "Widget", "overlay": true, "children": [
39
+ { "field.string": { "name": "notes" } }
40
+ ]}}
41
+ ]}}
42
+ """
43
+
44
+ EXTRA_YAML = "metadata:\n package: acme\n children: []\n"
45
+
46
+
47
+ def _project(tmp_path: Path) -> Path:
48
+ meta = tmp_path / "metaobjects"
49
+ meta.mkdir()
50
+ (meta / "meta.base.json").write_text(MESSY_WIDGET, encoding="utf-8")
51
+ (meta / "meta.already-canonical.json").write_text(CANONICAL_GADGET, encoding="utf-8")
52
+ (meta / "meta.widget.ui.json").write_text(OVERLAY_WIDGET_UI, encoding="utf-8")
53
+ (meta / "meta.extra.yaml").write_text(EXTRA_YAML, encoding="utf-8")
54
+ return meta
55
+
56
+
57
+ def test_reformats_messy_leaves_canonical_skips_overlay_and_yaml(tmp_path, monkeypatch, capsys) -> None:
58
+ meta = _project(tmp_path)
59
+ monkeypatch.chdir(tmp_path)
60
+
61
+ rc = main(["fmt"])
62
+ assert rc == 0
63
+
64
+ out = capsys.readouterr().out
65
+ assert "reformatted" in out
66
+ assert "skipped (yaml)" in out
67
+ assert "skipped (overlay)" in out
68
+
69
+ assert (meta / "meta.already-canonical.json").read_text(encoding="utf-8") == CANONICAL_GADGET
70
+ assert (meta / "meta.base.json").read_text(encoding="utf-8") != MESSY_WIDGET
71
+ assert (meta / "meta.widget.ui.json").read_text(encoding="utf-8") == OVERLAY_WIDGET_UI
72
+ assert (meta / "meta.extra.yaml").read_text(encoding="utf-8") == EXTRA_YAML
73
+
74
+ # The reformatted file round-trips to valid, equivalent JSON.
75
+ reformatted = json.loads((meta / "meta.base.json").read_text(encoding="utf-8"))
76
+ assert reformatted["metadata.root"]["package"] == "acme"
77
+
78
+
79
+ def test_is_idempotent(tmp_path, monkeypatch) -> None:
80
+ _project(tmp_path)
81
+ monkeypatch.chdir(tmp_path)
82
+ assert main(["fmt"]) == 0
83
+ once = (tmp_path / "metaobjects" / "meta.base.json").read_text(encoding="utf-8")
84
+ assert main(["fmt"]) == 0
85
+ assert (tmp_path / "metaobjects" / "meta.base.json").read_text(encoding="utf-8") == once
86
+
87
+
88
+ def test_check_mode_lists_drift_and_changes_nothing(tmp_path, monkeypatch, capsys) -> None:
89
+ meta = _project(tmp_path)
90
+ monkeypatch.chdir(tmp_path)
91
+ before = (meta / "meta.base.json").read_text(encoding="utf-8")
92
+
93
+ rc = main(["fmt", "--check"])
94
+ assert rc == 1
95
+ assert "not canonical" in capsys.readouterr().err
96
+
97
+ assert (meta / "meta.base.json").read_text(encoding="utf-8") == before
98
+
99
+
100
+ def test_check_mode_passes_once_canonical(tmp_path, monkeypatch) -> None:
101
+ _project(tmp_path)
102
+ monkeypatch.chdir(tmp_path)
103
+ assert main(["fmt"]) == 0
104
+ assert main(["fmt", "--check"]) == 0
105
+
106
+
107
+ def test_explicit_file_narrows_the_run(tmp_path, monkeypatch) -> None:
108
+ meta = _project(tmp_path)
109
+ monkeypatch.chdir(tmp_path)
110
+ before_base = (meta / "meta.base.json").read_text(encoding="utf-8")
111
+
112
+ rc = main(["fmt", "metaobjects/meta.already-canonical.json"])
113
+ assert rc == 0
114
+ # Untouched — only the named (already-canonical) file was in scope.
115
+ assert (meta / "meta.base.json").read_text(encoding="utf-8") == before_base
116
+
117
+
118
+ def test_explicit_file_outside_resolved_sources_fails(tmp_path, monkeypatch, capsys) -> None:
119
+ _project(tmp_path)
120
+ monkeypatch.chdir(tmp_path)
121
+ (tmp_path / "outside.json").write_text("{}", encoding="utf-8")
122
+
123
+ rc = main(["fmt", "outside.json"])
124
+ assert rc == 1
125
+ assert "not among this project's resolved metadata sources" in capsys.readouterr().err
126
+
127
+
128
+ def test_refuses_when_project_does_not_load_cleanly(tmp_path, monkeypatch, capsys) -> None:
129
+ meta = tmp_path / "metaobjects"
130
+ meta.mkdir()
131
+ (meta / "bad.json").write_text("{ this is not valid json", encoding="utf-8")
132
+ monkeypatch.chdir(tmp_path)
133
+
134
+ rc = main(["fmt"])
135
+ assert rc == 1
136
+ assert "does not currently load cleanly" in capsys.readouterr().err
137
+ assert (meta / "bad.json").read_text(encoding="utf-8") == "{ this is not valid json"