Skip to content

Add constructor-driven @Schemable and typed SchemaProvider<T>#93

Open
leoafarias wants to merge 9 commits intomainfrom
leoafarias/ack-api-review
Open

Add constructor-driven @Schemable and typed SchemaProvider<T>#93
leoafarias wants to merge 9 commits intomainfrom
leoafarias/ack-api-review

Conversation

@leoafarias
Copy link
Collaborator

@leoafarias leoafarias commented Mar 6, 2026

Summary

  • Redesign the schema annotation API around constructor-driven @Schemable and typed SchemaProvider<T>
  • Update generator resolution for constructor params, provider-based custom types, case styles, and prefixed imports
  • Migrate examples, docs, and tests to the provider-only surface and deprecate AckModel/AckField
  • Fix silent constraint discard when @EnumString was combined with other string constraints
  • Simplify generator internals: remove dead code, deduplicate helpers, and clean up unreachable branches

Changes

Annotations (ack_annotations)

  • New @Schemable annotation with useProviders, caseStyle, discriminatedKey/discriminatedValue, and schemaName
  • New parameter annotations: @SchemaConstructor, @SchemaKey, @Description
  • New SchemaProvider<T> interface for registering custom type schemas
  • Deprecate AckModel (now extends Schemable) and AckField

Generator (ack_generator)

  • Constructor-driven analysis: only named parameters from the selected constructor are included in the schema
  • Provider validation: concrete class, const constructor, correct AckSchema<T> return type, no duplicate targets
  • Import-prefix-aware type resolution for cross-file and prefixed schemable references
  • Case style key canonicalization (camelCase, snake_case, PascalCase, param-case)
  • Discriminator key canonicalization across sealed hierarchies
  • Detect and error on conflicting @EnumString + string constraint combinations
  • Deduplicate annotation utils, type resolver helpers, and remove dead code paths

Docs & Examples

  • Update API reference, configuration, and serialization docs for constructor-driven workflow
  • Migrate all examples to @Schemable with parameter annotations

Validation

dart format packages/ack_annotations packages/ack_generator example
dart analyze packages/ack_annotations packages/ack_generator example
cd packages/ack_generator && dart test

@docs-page
Copy link

docs-page bot commented Mar 6, 2026

To view this pull requests documentation preview, visit the following URL:

docs.page/btwld/ack~93

Documentation is deployed and generated using docs.page.

@leoafarias leoafarias requested a review from Copilot March 7, 2026 14:35
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR redesigns Ack’s annotation-driven schema generation around constructor-driven @Schemable() models and typed SchemaProvider<T> registrations, updating the generator plus repo docs/examples/tests to match the new surface.

Changes:

  • Introduces @Schemable + constructor-parameter annotations (@SchemaConstructor, @SchemaKey, @Description) and typed SchemaProvider<T>.
  • Refactors ack_generator analysis/resolution to be constructor-driven, adding provider- and prefix-aware type resolution plus case-style key canonicalization.
  • Migrates tests, examples, and docs from field-based @AckField usage to constructor-parameter metadata (and deprecates AckField / keeps AckModel as a compatibility alias).

Reviewed changes

Copilot reviewed 59 out of 59 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/ack_generator/test/test_utils/test_assets.dart Updates in-memory test packages to include new Schemable/provider/constraints APIs.
packages/ack_generator/test/src/test_utilities.dart Extends test mocks to support new FieldInfo fields/copying.
packages/ack_generator/test/src/generator_test.dart Updates constructor shapes in generator fixture sources.
packages/ack_generator/test/src/builders/schema_builder_test.dart Adjusts schema builder tests for new model registration behavior.
packages/ack_generator/test/src/builders/field_builder_test.dart Updates nested-schema tests to register models for resolution.
packages/ack_generator/test/src/analyzer/model_analyzer_test.dart Adds/updates tests for constructor selection, descriptions, providers, discriminator canonicalization.
packages/ack_generator/test/src/analyzer/field_analyzer_test.dart Migrates field analysis tests to constructor-parameter analysis (SchemaKey, constraints, defaults).
packages/ack_generator/test/integration/schemable_provider_resolution_test.dart New integration coverage for provider registration (same-file/imported/prefixed/mixin/base-class).
packages/ack_generator/test/integration/schemable_cross_file_resolution_test.dart New integration coverage for cross-file/prefixed schemable type references.
packages/ack_generator/test/integration/nested_model_test.dart Formatting/expectation updates to align with new generator behavior.
packages/ack_generator/test/integration/complex_model_test.dart Migrates constraints/keys expectations from field-based to parameter-based generation.
packages/ack_generator/test/enum_test.dart Minor formatting updates in enum generation tests.
packages/ack_generator/test/enhanced_error_messages_test.dart Updates legacy-API failure messaging to match removed annotation shape.
packages/ack_generator/test/description_generation_test.dart Replaces extensive legacy description tests with Schemable/parameter-driven description coverage.
packages/ack_generator/test/correctness_fixes_test.dart Updates discriminated examples and description/constraint sources to constructor-param annotations.
packages/ack_generator/test/annotation_combination_edge_cases_test.dart Replaces AckModel/AckField combinations with Schemable constructor-contract edge cases + error logging.
packages/ack_generator/test/additional_properties_args_test.dart Test formatting updates; ensures args getter behavior remains stable.
packages/ack_generator/test/ack_field_comprehensive_test.dart Replaces AckField comprehensive tests with constructor-contract/provider/error scenarios.
packages/ack_generator/lib/src/validation/model_validator.dart Formatting-only change.
packages/ack_generator/lib/src/utils/type_resolver.dart New resolver for primitives/collections/enums/schemables/providers (incl. prefixed type names).
packages/ack_generator/lib/src/utils/case_style_utils.dart New case-style transformation utilities for schema key generation.
packages/ack_generator/lib/src/utils/annotation_utils.dart New shared helpers for finding annotations, schema names, and import-prefix detection.
packages/ack_generator/lib/src/models/type_provider_info.dart New model for provider metadata + stable identity keying for generic targets.
packages/ack_generator/lib/src/models/model_info.dart Adds typeProviders to model metadata and updates docs/comments.
packages/ack_generator/lib/src/models/field_info.dart Adds schemaExpressionOverride and a copyWith helper.
packages/ack_generator/lib/src/generator.dart Switches class discovery/error messaging to @Schemable (with legacy alias support).
packages/ack_generator/lib/src/builders/schema_builder.dart Uses shared schema-variable naming + simplifies discriminated/object schema building.
packages/ack_generator/lib/src/builders/field_builder.dart Replaces ad-hoc type mapping with resolver + supports schema-expression overrides.
packages/ack_generator/lib/src/analyzer/model_analyzer.dart Major refactor: constructor selection, named-parameter enforcement, provider validation, discriminator canonicalization.
packages/ack_generator/lib/src/analyzer/field_analyzer.dart Refactor: analyzes constructor parameters (SchemaKey, Description, typed constraint annotations, caseStyle).
packages/ack_generator/README.md Rewrites docs to describe constructor-driven Schemable + providers and deprecate legacy usage.
packages/ack_annotations/pubspec.yaml Adds a direct dependency on ack for SchemaProvider/AckSchema types.
packages/ack_annotations/lib/src/schemable.dart New Schemable annotation surface + SchemaProvider contract and parameter annotations.
packages/ack_annotations/lib/src/constraints.dart Retargets constraint annotations from fields to constructor parameters.
packages/ack_annotations/lib/src/ack_type.dart Updates docs to reference Schemable instead of AckModel in guidance.
packages/ack_annotations/lib/src/ack_model.dart Deprecates AckModel and makes it extend Schemable as a compatibility alias.
packages/ack_annotations/lib/src/ack_field.dart Deprecates AckField / required-mode enum to reflect removal from generator surface.
packages/ack_annotations/lib/ack_annotations.dart Exports new Schemable + constraints surface.
packages/ack_annotations/README.md Updates docs to constructor contract, parameter annotations, providers, and compatibility notes.
example/test/comprehensive_model_test.dart Updates narrative/comments for schema-first validation phrasing.
example/lib/validation_test_model.dart Migrates commented and active annotations to Schemable.
example/lib/test_extension_types.dart Migrates example models from AckModel to Schemable.
example/lib/status_model.dart Moves EnumString usage from field to constructor parameter and switches to Schemable.
example/lib/special_types_model.dart Migrates to Schemable.
example/lib/simple_examples.g.dart Updates generated schema output to match new constructor-requiredness behavior.
example/lib/simple_examples.dart Migrates examples to Schemable.
example/lib/product_model.dart Moves constraints onto constructor parameters; migrates to Schemable.
example/lib/mixed_examples.dart Migrates examples to Schemable; moves EnumString constraint to parameter.
example/lib/edge_case_models.dart Migrates to Schemable; replaces AckField jsonKey usage with SchemaKey parameters.
example/lib/discriminated_example.g.dart Updates generated output for defaulted parameters now treated as optional.
example/lib/discriminated_example.dart Migrates discriminated hierarchies to sealed + Schemable.
example/lib/described_model.dart Moves descriptions/constraints to constructor parameter annotations.
example/lib/anyof_example.g.dart Updates generated output to use provider schemas for anyOf wrapper types.
example/lib/anyof_example.dart Adds SchemaProvider implementations + registers them via useProviders; migrates to Schemable.
docs/core-concepts/typesafe-schemas.mdx Updates docs to reference Schemable constructor-driven generation.
docs/core-concepts/json-serialization.mdx Updates codegen section for Schemable + constructor-driven behavior.
docs/core-concepts/configuration.mdx Updates configuration guidance for parameter annotations and constructor contract rules.
docs/api-reference/index.mdx Updates API reference to Schemable + adds docs for new annotations/providers.
Comments suppressed due to low confidence (1)

packages/ack_generator/lib/src/analyzer/model_analyzer.dart:74

  • additionalPropertiesField is validated against a class field name, but the schema-generation skip logic compares it to fieldInfo.name (the selected constructor parameter name). If the extra-properties map is assigned via a differently named constructor parameter (e.g. initializer list) the field will incorrectly be emitted into the schema. Consider validating that the selected constructor has a parameter matching additionalPropertiesField (or that it’s an initializing formal for that field), and/or skipping based on the resolved field being assigned rather than only the parameter name.
      if (additionalPropertiesField != null &&
          fieldInfo.name == additionalPropertiesField) {
        continue;
      }

Comment on lines 35 to 38
'enumString': (_, args) {
final values = args.map((v) => "'$v'").join(', ');
return 'Ack.enumString([$values])';
},
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The enumString constraint builder replaces the in-progress schema with Ack.enumString(...), which means any constraints added before it (e.g. @MinLength, @Pattern, @Email) are silently discarded due to the current constraint ordering. Either apply EnumString first (so subsequent constraints can chain), or detect/forbid mixing EnumString with other string constraints and throw a clear error.

Copilot uses AI. Check for mistakes.
Remove dead code, deduplicate helpers, and detect conflicting
@EnumString + string constraint combinations that were silently
discarded during schema generation.
@leoafarias leoafarias changed the title Redesign Schemable around typed schema providers Add constructor-driven @Schemable and typed SchemaProvider<T> Mar 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants