Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b3caec7
feat!: consolidate Ack 2.0 single-part codegen and Draft 2020-12 runtime
leoafarias Oct 9, 2026
4d70eea
refactor(ack): unify native and imported multipleOf on exact decimal …
leoafarias Oct 9, 2026
05ab5b6
style: format workspace with dart format
leoafarias Oct 9, 2026
0dd6677
Merge remote-tracking branch 'origin/main' into leoafarias/ack-2-0-pr…
leoafarias Oct 9, 2026
0dfbf93
feat(ack)!: preserve Draft 2020-12 by default on toJsonSchema and toS…
leoafarias Oct 9, 2026
092ed37
feat(ack,ack_generator): unify constraint annotations under @Check.* …
leoafarias Oct 9, 2026
43d3698
feat(ack): seal SchemaError and AckSchema hierarchies
leoafarias Oct 9, 2026
309d494
feat(ack,ack_generator): make trim, toLowerCase, and toUpperCase two-…
leoafarias Oct 9, 2026
047b807
test(ack_generator): align exports and guide integration tests with @…
leoafarias Oct 9, 2026
39ae10e
Merge remote-tracking branch 'origin/main' into leoafarias/ack-2-0-pr…
leoafarias Oct 9, 2026
9e77a96
feat(ack): add StandardSchemaV1 interoperability contract (#129)
leoafarias Oct 10, 2026
556e426
feat(ack,ack_generator): add JsonMaybe<T> for PATCH key presence (#148)
leoafarias Oct 10, 2026
5f71972
feat(ack,ack_generator): enforce type-owned schema bounds/boundaries …
leoafarias Oct 10, 2026
90eebfa
feat(ack,ack_generator): support @Schemable(schemas: [...]) + auto li…
leoafarias Oct 10, 2026
66cb812
docs,test(ack_generator): align READMEs, docs, and llms.txt with Ack …
leoafarias Oct 10, 2026
1ace93b
chore(release): prepare Ack 2.0.0-beta.1
leoafarias Oct 10, 2026
7bde538
ci: remove consolidated json_schema_format_import_test from Chrome list
leoafarias Oct 10, 2026
5b11c5a
feat(ack,ack_generator)!: rename @Check to @Validate and polish class…
leoafarias Oct 10, 2026
b66b26f
refactor!: complete 2.0 reference design audit, API cleanup, and code…
leoafarias Oct 11, 2026
a764f47
refactor(ack,ack_generator): decompose model graph builders, emitters…
leoafarias Oct 11, 2026
4f1c54d
fix(ack_generator): read AST doc comments on primary constructor decl…
leoafarias Oct 12, 2026
38af885
chore(ack_generator): widen analyzer constraint to >=10.0.0 <15.0.0 f…
leoafarias Oct 12, 2026
cabd6cd
chore(ack_generator): migrate AST helpers to analyzer 13
leoafarias Oct 12, 2026
d616763
fix(ack,ack_generator): harden JSON Schema export composition, Draft-…
leoafarias Oct 12, 2026
0f508da
fix(ack): preserve source allOf when layering conflicting constraints
leoafarias Oct 12, 2026
2c2baa9
chore(ack): pin Flutter 3.47.5 in .fvmrc and update ack_generator tes…
leoafarias Oct 12, 2026
dcaf31d
docs: add migration guide, ecosystem integrations guide, and merge v1…
leoafarias Oct 12, 2026
5608c4f
chore(ci): add Flutter 3.47.5 to flutter-releases.json and format wit…
leoafarias Oct 12, 2026
b5045ff
refactor(ack)!: unify @Validate.optional, @Validate.required, and @Va…
leoafarias Oct 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .fvmrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"flutter": "3.41.2"
"flutter": "3.47.5"
}
4 changes: 4 additions & 0 deletions .github/flutter-releases.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
"3.41.2": {
"dart": "3.11.0",
"sha256": "4a04f8a6152986d14fc137ffaf98106ca743c0f9ab66f1bc2f20ee84eb573e5c"
},
"3.47.5": {
"dart": "3.13.4",
"sha256": "2132e990f236f8d22e7c6314b29a191a95b10d7cbcfec9b4e2e303d996652cbb"
}
}
}
3 changes: 1 addition & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ jobs:
test/schemas/extensions/list_schema_extensions_test.dart \
test/utils/collection_utils_test.dart \
test/json_schema_import_test.dart \
test/json_schema_import_api_test.dart \
test/json_schema_format_import_test.dart
test/json_schema_import_api_test.dart

- name: Test JSON Schema import bridge in Chrome
working-directory: packages/ack_json_schema_builder
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/preflight.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ env:
# against the change severity, so a breaking change requires a major bump.
API_BASELINE_VERSION: '1.6.2'
# The lowest SDK versions that packages/*/pubspec.yaml accept.
MINIMUM_DART_VERSION: '3.9.0'
MINIMUM_FLUTTER_VERSION: '3.35.0'
MINIMUM_DART_VERSION: '3.11.0'
MINIMUM_FLUTTER_VERSION: '3.41.2'


jobs:
minimum-dart-sdk:
Expand Down Expand Up @@ -192,13 +193,12 @@ jobs:
- name: Resolve workspace dependencies
run: dart pub get

# `.ack.dart` holds the generated models and `.ack.g.dart` holds the JSON
# mapping. Both are generated, so a clean rebuild must reproduce them.
# The `*.g.dart` glob below also matches `*.ack.g.dart`.
# `.g.dart` holds the generated Ack models, schemas, and JSON mapping.
# A clean rebuild must reproduce them identically.
- name: Delete the committed generator output
run: |
set -euo pipefail
git ls-files -z -- '*.ack.dart' '*.g.dart' \
git ls-files -z -- '*.g.dart' \
| xargs -0 --no-run-if-empty rm --

- name: Regenerate from a clean tree
Expand Down
89 changes: 89 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,95 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## 2.0.0-beta.1

### Breaking & Substitutions

* **Single `.g.dart` part & direct JSON emitter (`#189`)**: `ack_generator:ack_generator`
now emits a single `<file>.g.dart` part via `SharedPartBuilder` with direct
`toJson()` / `fromJson()` helpers (no `json_serializable` or `json_annotation`
dependency).
* **Substitute:** Replace `part '<file>.ack.dart';` + `part '<file>.ack.g.dart';`
with `part '<file>.g.dart';`.
* **Substitute:** Replace `ack_generator|ack_models` and
`ack_generator|ack_model_json` in `build.yaml` with
`ack_generator|ack_generator`.
* **Unified `@Validate.*` presence & constraint namespace (`#191`)**: Removed the
top-level presence classes (`@Optional`, `@Required`, `@NotNull`), the 18
`@Deprecated` 1.x top-level constraint classes (`@Min`, `@Max`, `@Email`, etc.),
and `package:ack/format_annotations.dart`.
* **Substitute:** Use `@Validate.<name>(...)` from `package:ack/ack.dart`
(`@Validate.optional()`, `@Validate.required()`, `@Validate.notNull()`,
`@Validate.min(...)`, `@Validate.max(...)`, `@Validate.multipleOf(...)`,
`@Validate.positive()`, `@Validate.negative()`, `@Validate.minLength(...)`,
`@Validate.maxLength(...)`, `@Validate.matches(...)`, `@Validate.notEmpty()`,
`@Validate.email()`, `@Validate.url()`, `@Validate.uuid()`, `@Validate.date()`,
`@Validate.dateTime()`, `@Validate.uri()`, `@Validate.ip()`, `@Validate.ipv4()`,
`@Validate.ipv6()`, `@Validate.minItems(...)`, `@Validate.maxItems(...)`,
`@Validate.uniqueItems()`).
* **Removed legacy 1.x generator annotations & shims (`#188`, `#189`)**:
Removed `@AckType`, `@AckInfer`, `@AckModel`, `JsonKeyCaseStyle`, `AckTypeDef`,
`AckFieldPresence`, `*Type` extension-type models, and the `@JsonKey(name: ...)`
fallback.
* **Substitute:** Use `@Schemable()` on schemas and classes,
`@Validate.optional()` / `@Validate.required()` / `@Validate.notNull()` for
field presence, and `@AckField(name: '...')` for wire-name overrides.
* **Removed redundant helpers & `StandardSchemaV1` (`#129`)**:
* **Substitute:** `Ack.enumCodec(E.values)` $\rightarrow$ `Ack.enumValues(E.values)`.
* **Substitute:** `registerAckModelTool(...)` $\rightarrow$
`registerAckTool(..., input: Model.schema)`.
* **Substitute:** `convertAckSchemaModelToBuilder(m)` $\rightarrow$
`schema.toJsonSchemaBuilder()`.
* **Substitute:** `StandardSchemaV1` $\rightarrow$ `AckSchema<Boundary, Runtime>`
+ `SchemaResult<T>`.
* **Sealed `SchemaError` & `AckSchema` hierarchies + decoder `Error` propagation (`#163`)**:
`SchemaError` and `AckSchema` are now `sealed class`es for exhaustive pattern
matching. `CodecSchema` rethrows programmer `Error`s during `parse` /
`safeParse` (matching `encode` / `safeEncode`) and catches only `Exception`s
as `SchemaTransformError`.
* **JSON Schema Draft 2020-12 default export & `format` annotation mode (`#171`, `#186`)**:
`Ack.fromJsonSchema()` defaults to `assertFormats: false` (pass
`assertFormats: true` or declare the `format-assertion` vocabulary to enforce
format assertions). `toJsonSchema()`, `toSchemaModel()`, and
`toJsonSchemaBuilder()` preserve imported Draft 2020-12 resources by default;
use `toJsonSchemaDraft7()`, `toSchemaModelDraft7()`, or
`toJsonSchemaBuilderDraft7()` when legacy Draft-07 lowering is needed.

### Added

* **`JsonMaybe<T>` tri-state presence (`#148`)**: `sealed class JsonMaybe<T>`
(`JsonAbsent<T>`, `JsonValue<T>`) distinguishes omitted keys (`JsonAbsent`),
explicit `null` (`JsonValue(null)`), and present values (`JsonValue(v)`) in
`@Schemable()` class-first models for `PATCH` payloads.
* **Layered custom schema resolution (`#185`)**: Class-first `@Schemable()`
fields resolve custom types via `@AckField(schema: ...)`,
`@Schemable(schemas: [...])` (on classes, unions, or `library;` directives),
type-owned `T.schema` / `T.schema<...>()` factories, or automatic detection of
a unique top-level `AckSchema<Boundary, T>` in the current library.
* **Two-way `StringSchema` normalizers**: `.trim()`, `.toLowerCase()`, and
`.toUpperCase()` execute in declaration order during both `parse` and `encode`,
preserve `StringSchema` chaining, work in `@Schemable()` models, and export as
`type: 'string'` without `'x-transformed': true`.
* **Full JSON Schema Draft 2020-12 runtime & `.schema.json` generator (`#167`, `#171`, `#186`)**:
Supports `$dynamicRef`, `$dynamicAnchor`, `unevaluatedProperties`,
`unevaluatedItems`, `prefixItems`, `dependentRequired`, `dependentSchemas`,
`patternProperties`, `minContains`, `maxContains`, bundled offline 2020-12
meta-schemas, and all 19 Draft 2020-12 formats. Opt-in
`ack_generator:ack_json_schema` compiles `lib/**/*.schema.json` into
`<name>.schema.dart` + `<name>.schema.g.dart`.

### Fixed

* Explicit Draft-7 export rejects unsupported Draft 2020-12 assertions rather
than emitting keywords that Draft-7 validators ignore.
* Imported schema exports preserve JSON Pointer targets through retrieval URI
aliases, share identical identified resources across composed imports, and
preserve occurrence-level nullability and constraints (including source
`allOf` when layering conflicting constraints).
* Preserve integral decimal length and item bounds in `.schema.json` generation,
and use validated value models for Unicode regex patterns and named scalar
unions.

## 1.7.0

* Remove `ack_annotations`; annotations now ship in `ack` (`package:ack/ack.dart`,
Expand Down
38 changes: 17 additions & 21 deletions PUBLISHING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,17 @@ new compatible features/packages, and major when any stable public API breaks.
For 1.7.0, the imported-pattern Unicode behavior change is a deliberately
accepted exception to this major-version policy.

The next release is **1.7.0**, promoting the 1.7.0 beta series to stable across
all five publishable packages. It ships annotations in `package:ack`, unifies
model and schema generation on `@Schemable()`, adds `multipleOf`, `contains`,
`if`/`then`/`else`, built-in `format` assertions, `x-*` vendor extension
tolerance, Draft-07 `$schema` URI support, and `JsonSchemaValidationError`
diagnostics (`keyword`, `keywordLocation`, `documentUri`, `pointer`) to
`Ack.fromJsonSchema()`, and speeds up validation and JSON Schema export.
The beta.5 imported-pattern change to ECMA-262 Unicode mode applies when
upgrading from stable 1.6.2 or earlier 1.7.0 betas; review imported patterns,
including identity escapes and expressions that count UTF-16 code units. Native
`Ack.string().matches()` keeps its Dart regex contract. The beta.3 annotation
and generator migration applies to consumers coming from 1.6.2 or earlier
betas. The API check compares all five packages against 1.6.2; generator
compatibility also requires the consumer build and runtime tests because the
API check cannot inspect generated consumer code.
The next candidate is **2.0.0-beta.1**. It introduces single-pass `.g.dart`
code generation without a runtime `json_serializable` delegation step, the
unified `@Validate.*` constraint annotation namespace, custom schema resolution
via `@Schemable(schemas: [...])` and automatic same-library detection,
`JsonMaybe<T>` PATCH presence semantics, two-way `StringSchema` normalizers
(`.trim()`, `.toLowerCase()`, `.toUpperCase()`), sealed `SchemaError` and
`AckSchema` hierarchies, full JSON Schema Draft 2020-12 runtime validation and
`.schema.json` model generation with default Draft 2020-12 preservation on
`toJsonSchema()`, and removal of deprecated 1.x compatibility shims
(`StandardSchemaV1`, `@AckType`, `@AckInfer`, `@AckModel`, and `.ack.dart` /
`.ack.g.dart` dual-part generation).

The shared API baseline for this release is 1.6.2. Confirm that all five
packages have published 1.6.2 versions before preparing the release.
Expand Down Expand Up @@ -61,7 +57,7 @@ References: [Melos versioning](https://melos.invertase.dev/commands/version),
3. Preview/prepare a coordinated version without creating commits or tags:

```sh
dart run melos version --manual-version=ack:1.7.0 --yes --no-git-commit-version
dart run melos version --manual-version=ack:2.0.0-beta.1 --yes --no-git-commit-version
```

Use the named flag, not a positional package argument: the positional form
Expand All @@ -88,7 +84,7 @@ References: [Melos versioning](https://melos.invertase.dev/commands/version),
7. Validate the complete release from that clean commit:

```sh
dart scripts/verify_release_tag.dart v1.7.0 --skip-ancestry
dart scripts/verify_release_tag.dart v2.0.0-beta.1 --skip-ancestry
dart run melos run ci
dart scripts/api_check.dart 1.6.2
dart scripts/publish_dry_run.dart
Expand Down Expand Up @@ -142,9 +138,9 @@ After the release commit's CI/preflight succeeds:
```sh
git fetch origin main --tags
# Use the exact reviewed release merge commit, not an arbitrary later main head.
git tag -a v1.7.0 <release-merge-sha> -m 'Ack 1.7.0'
dart scripts/verify_release_tag.dart v1.7.0
git push origin v1.7.0
git tag -a v2.0.0-beta.1 <release-merge-sha> -m 'Ack 2.0.0 beta 1'
dart scripts/verify_release_tag.dart v2.0.0-beta.1
git push origin v2.0.0-beta.1
```

Pushing the tag triggers `.github/workflows/release.yml`; there is no Melos
Expand Down Expand Up @@ -174,4 +170,4 @@ After all five exact versions are visible, create the GitHub Release from the
existing tag using the prepared release notes and mark it as a prerelease for
beta versions. Before the first subsequent code
change, begin a new unreleased changelog section instead of editing the
1.7.0 notes.
2.0.0-beta.1 notes.
75 changes: 20 additions & 55 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,14 @@ if (result.isOk) {

Generate immutable models for hand-written schemas with `@Schemable()`. Add
`ack` to `dependencies` and `ack_generator` + `build_runner` to
`dev_dependencies`, then annotate a top-level schema. `@Schemable()` comes
from `package:ack/ack.dart`; constraint annotations such as `@MinLength()` come
from `package:ack/annotations.dart`:
`dev_dependencies`, then annotate a top-level schema. `@Schemable()`, the model
annotations (`@AckField`, `@Optional`, `@Required`, `@NotNull`), and the
`@Validate.*` constraint namespace are all exported from `package:ack/ack.dart`:

```dart
import 'package:ack/ack.dart';

part 'user.ack.dart';
part 'user.ack.g.dart';
part 'user.g.dart';

@Schemable()
final userSchema = Ack.object({
Expand Down Expand Up @@ -160,73 +159,39 @@ named recursion, and discriminated unions. One-way transforms are rejected
because a generated model must be encodable. See the
[Model Code Generation guide](docs/core-concepts/typesafe-schemas.mdx).

### Legacy Ack 1.1 generation

`@AckType()` remains available for source compatibility and keeps the Ack 1.1
extension-type API and `.g.dart` output unchanged. It is deprecated and will be
removed in Ack 2.0:

```dart
import 'package:ack/ack.dart';
import 'package:ack/annotations.dart';

part 'legacy_user.g.dart';

@AckType()
final userSchema = Ack.object({'name': Ack.string()});
```

This still generates `UserType`, including its Map interface, typed getters,
`parse` / `safeParse`, and `.args`. New code should use `@Schemable()`.

| Ack 1.1 source | Optional immutable-model migration |
|---|---|
| Keep `@AckType()` | Rename it to `@Schemable()` |
| Keep `part 'file.g.dart';` | Add `file.ack.dart` and `file.ack.g.dart` parts |
| Use `*Type`, Map access, and `.args` | Use the generated class, typed fields, `parse`, `fromJson`, and `toJson` |

Legacy and modern declarations may coexist when they are unrelated. A nested
reference graph cannot cross between them; migrate that connected graph
together.

Already own the model class? Put `@Schemable()` on it to derive a codec schema from
constructor-backed fields while keeping the class hand-written. A class named
`Account` receives an `AccountSchema` facade for parsing, encoding, schema
export, and nested composition; the backing codec remains private:
constructor-backed fields (including Dart 3.12+ primary constructors) while
keeping the class hand-written. A class named `Account` receives a private
`_accountSchema` codec and a public `AccountSchema` facade for parsing, encoding,
schema export, and nested composition:

```dart
import 'package:ack/ack.dart';
import 'package:ack/annotations.dart';

part 'account.g.dart';

@Schemable()
final class Account with _$AccountAck {
const Account({required this.name});

@MinLength(2)
@Validate.minLength(2)
final String name;

static final schema = _accountSchema;
static final fromJson = AccountSchema.fromJson;
}
```

`Account.fromJson({'name': 'Ada'})` validates and constructs the model, while
`account.toJson()` validates and encodes it.
`Account.fromJson({'name': 'Ada'})` (or `Account.schema.parse(...)`) validates
and constructs the model, while `account.toJson()` validates and encodes it.

A field whose type declares a static `schema` needs no annotation: a `Slot`
field resolves to `Slot.schema`, a `List<Slot>` to `Ack.list(Slot.schema)`,
and a generic `Command<Action>` to `Command.schema<Action>()`. See the
Custom field types resolve automatically through a static `schema` on the type
(`Slot.schema`, `Ack.list(Slot.schema)`, `Command.schema<Action>()`), a unique
top-level `AckSchema<Boundary, T>` in the same library, `@Schemable(schemas: [...])`
on the class, union, or `library;` directive, or `@AckField(schema: ...)` on a
specific field. See the
[Model Code Generation guide](docs/core-concepts/typesafe-schemas.mdx).

Upgrading from 1.6.x: drop `ack_annotations`, import
`package:ack/ack.dart` for `@Schemable()`, and replace
`package:ack_annotations/ack_annotations.dart` with
`package:ack/annotations.dart` (and `.../format_annotations.dart` with
`package:ack/format_annotations.dart`) where you use constraint annotations.
Rename `@Pattern` to `@Matches`, and replace the deprecated `@AckInfer()` /
`@AckModel()` with `@Schemable()`. A field renamed with `@JsonKey(name: ...)`
now imports `JsonKey` from `package:json_annotation`, with `json_annotation`
in the app's dependencies.

## Codecs

Codecs decode boundary values (the JSON you receive) into rich Dart runtime types and encode them back. Ack ships built-in codecs and lets you define your own:
Expand All @@ -237,7 +202,7 @@ final when = Ack.datetime();
final dt = when.parse('2026-01-01T00:00:00Z'); // DateTime
final iso = when.encode(dt); // back to an ISO 8601 String

// Other built-ins: Ack.date(), Ack.uri(), Ack.duration(), Ack.enumCodec(...)
// Other built-ins: Ack.date(), Ack.uri(), Ack.duration()

// Custom bidirectional codec
final csv = Ack.codec<String, String, List<String>>(
Expand Down
14 changes: 11 additions & 3 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
{
"title": "Quickstart Tutorial",
"href": "/getting-started/quickstart-tutorial"
},
{
"title": "What's New & Migration Guide",
"href": "/getting-started/migration-guide"
}
]
},
Expand All @@ -51,7 +55,11 @@
"href": "/guides/flutter-form-validation"
},
{ "title": "Common Recipes", "href": "/guides/common-recipes" },
{ "title": "Custom Validation", "href": "/guides/custom-validation" }
{ "title": "Custom Validation", "href": "/guides/custom-validation" },
{
"title": "Ecosystem Integrations",
"href": "/guides/ecosystem-integrations"
}
]
},
{
Expand Down Expand Up @@ -89,8 +97,8 @@
],
"variables": {
"versions": {
"default": "1.2.0",
"isPrerelease": false
"default": "2.0.0-beta.1",
"isPrerelease": true
}
},
"search": {},
Expand Down
Loading
Loading