Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
118 changes: 86 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,31 @@
[![pub package](https://img.shields.io/pub/v/ack.svg)](https://pub.dev/packages/ack)
[![llms.txt](https://img.shields.io/badge/llms.txt-available-8A2BE2)](https://docs.page/btwld/ack/llms.txt)

Ack is a schema validation library for Dart and Flutter that helps you validate data with a simple, fluent API. Ack is short for "acknowledge".
Ack is a schema validation library for Dart and Flutter. It validates data with a fluent API. Ack is short for "acknowledge".

For AI agents: start at [`/llms.txt`](https://docs.page/btwld/ack/llms.txt).

## Why Use Ack?
## Why use Ack?

- **Simplify Validation**: Easily handle complex data validation logic
- **Validate external payloads**: Guard API and user inputs by validating
required fields, types, and constraints at boundaries
- **Single Source of Truth**: Define data structures and rules in one place
- **Reduce Boilerplate**: Minimize repetitive code for validation and JSON conversion
- **Type Safety**: Generate typed wrappers for hand-written Ack schemas with `@AckType()`
- **Validate external payloads**: Guard API and user inputs by validating required fields, types, and constraints at boundaries
- **Single source of truth**: Define data structures and rules in one place
- **Less boilerplate**: Minimize repetitive validation and JSON conversion code
- **Type safety**: Generate typed wrappers for hand-written Ack schemas with `@AckType()`

## Packages

This repository is a monorepo containing:

- **[ack](./packages/ack)**: Core validation library with fluent schema building API
- **[ack_generator](./packages/ack_generator)**: Code generator for `@AckType()` extension-type wrappers
- **[ack_firebase_ai](./packages/ack_firebase_ai)**: Firebase AI (Gemini) schema converter for structured output generation
- **[ack](./packages/ack)**: Core validation library with a fluent schema-building API, codecs, and JSON Schema export
- **[ack_annotations](./packages/ack_annotations)**: The `@AckType()` annotation that marks schemas for code generation
- **[ack_generator](./packages/ack_generator)**: Code generator that turns `@AckType()` schemas into type-safe extension types
- **[ack_firebase_ai](./packages/ack_firebase_ai)**: Firebase AI (Gemini) schema converter for structured-output generation
- **[ack_json_schema_builder](./packages/ack_json_schema_builder)**: Converter to `json_schema_builder` schemas
- **[example](./example)**: Example projects demonstrating usage of all packages

## Quick Start
## Quick start

### Core Library (ack)
### Core library (ack)

Add Ack to your project:

Expand All @@ -42,21 +42,18 @@ Define and use a schema:
```dart
import 'package:ack/ack.dart';

// Define a schema for a user object
final userSchema = Ack.object({
'name': Ack.string().minLength(2).maxLength(50),
'email': Ack.string().email(),
'age': Ack.integer().min(0).max(120).optional(),
});

// Validate data against the schema
final result = userSchema.safeParse({
'name': 'John Doe',
'email': 'john@example.com',
'age': 30
});

// Check if validation passed
if (result.isOk) {
final validData = result.getOrThrow();
print('Valid user: $validData');
Expand All @@ -68,9 +65,9 @@ if (result.isOk) {

Use `.optional()` when a field may be omitted entirely. Chain `.nullable()` if a present field may hold `null`, or combine both for an optional-and-nullable value.

### Advanced Usage
### Advanced usage

For more complex validation scenarios:
For complex validation:

```dart
import 'package:ack/ack.dart';
Expand Down Expand Up @@ -114,11 +111,71 @@ if (result.isOk) {
}
```

## Code generation

Generate type-safe wrappers for hand-written schemas with `@AckType()`. Add
`ack_annotations` to `dependencies` and `ack_generator` + `build_runner` to
`dev_dependencies`, then annotate a top-level schema:

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

part 'user.g.dart';

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

Run the generator:

```bash
dart run build_runner build --delete-conflicting-outputs
```

This emits a `UserType` extension type with `parse`/`safeParse` and typed
getters — no manual casting:

```dart
final user = UserType.parse({'name': 'Alice', 'email': 'alice@example.com'});
print(user.name); // typed String getter
```

`@AckType()` supports objects, primitives, lists, enums, explicit transforms, and discriminated unions. See the [TypeSafe Schemas guide](https://docs.page/btwld/ack/core-concepts/typesafe-schemas).

## 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:

```dart
// Built-in codec: ISO 8601 String boundary <-> UTC DateTime runtime
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(...)

// Custom bidirectional codec
final csv = Ack.codec<String, String, List<String>>(
input: Ack.string(),
decode: (s) => s.split(','),
encode: (list) => list.join(','),
);

csv.parse('a,b,c'); // ['a', 'b', 'c']
csv.encode(['a', 'b', 'c']); // 'a,b,c'
```

Use `.transform<R>(...)` for one-way (parse-only) conversions. See the
[Codecs guide](https://docs.page/btwld/ack/core-concepts/codecs).

## Documentation

Documentation endpoints:
- Human docs: [docs.page/btwld/ack](https://docs.page/btwld/ack)
- AI agent index (stable URL): [docs.page/btwld/ack/llms.txt](https://docs.page/btwld/ack/llms.txt)
- AI agent index: [docs.page/btwld/ack/llms.txt](https://docs.page/btwld/ack/llms.txt)
- Canonical plaintext source: [raw.githubusercontent.com/btwld/ack/main/llms.txt](https://raw.githubusercontent.com/btwld/ack/main/llms.txt)

## Development
Expand All @@ -135,7 +192,7 @@ dart pub global activate melos
melos bootstrap
```

### Common Commands (run from root)
### Common commands (run from root)

```bash
# Run tests across all packages
Expand Down Expand Up @@ -166,35 +223,32 @@ melos version
melos run publish
```

### Development Tools

The project includes additional development tools for maintainers:
### Development tools

```bash
# JSON Schema validation (ensures compatibility with JSON Schema Draft-7)
# JSON Schema validation (JSON Schema Draft-7 compatibility)
melos validate-jsonschema

# API compatibility checking using Dart script (for semantic versioning)
# API compatibility check (for semantic versioning)
melos api-check v0.2.0

# See all available scripts
melos list-scripts
```

> **Note**: Additional development documentation is available in the `tools/` directory for project maintainers.
Additional development documentation is available in the `tools/` directory.

## Versioning and Publishing
## Versioning and publishing

This project uses GitHub Releases to manage versioning and publishing. For detailed instructions on how to create releases and publish packages, see [PUBLISHING.md](./PUBLISHING.md).
This project uses GitHub Releases to manage versioning and publishing. See [PUBLISHING.md](./PUBLISHING.md) for instructions.

## Contributing

Contributions are welcome! A detailed CONTRIBUTING.md file will be added soon with specific guidelines.
Contributions are welcome. Follow these steps:

In the meantime, please follow these basic steps:
1. Fork the repository
2. Create a feature branch
3. Add your changes
4. Run tests with `melos test`
5. Make sure to follow [Conventional Commits](https://www.conventionalcommits.org/) in your commit messages
5. Follow [Conventional Commits](https://www.conventionalcommits.org/) in your commit messages
6. Submit a pull request
31 changes: 19 additions & 12 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,34 +31,41 @@
]
},
{
"group": "Core Concepts",
"group": "Essentials",
"pages": [
{ "title": "Schema Types", "href": "/core-concepts/schemas" },
{ "title": "Validation Rules", "href": "/core-concepts/validation" },
{
"title": "TypeSafe Schemas",
"href": "/core-concepts/typesafe-schemas"
},
{ "title": "Error Handling", "href": "/core-concepts/error-handling" },
{
"title": "JSON Serialization",
"href": "/core-concepts/json-serialization"
}
]
},
{
"group": "How-To Guides",
"pages": [
{
"title": "Flutter Form Validation",
"href": "/guides/flutter-form-validation"
},
{ "title": "Configuration", "href": "/core-concepts/configuration" }
{ "title": "Common Recipes", "href": "/guides/common-recipes" },
{ "title": "Custom Validation", "href": "/guides/custom-validation" }
]
},
{
"group": "Guides",
"group": "Advanced",
"pages": [
{ "title": "Custom Validation", "href": "/guides/custom-validation" },
{ "title": "Codecs", "href": "/core-concepts/codecs" },
{
"title": "TypeSafe Schemas",
"href": "/core-concepts/typesafe-schemas"
},
{
"title": "JSON Schema Integration",
"href": "/guides/json-schema-integration"
},
{
"title": "Flutter Form Validation",
"href": "/guides/flutter-form-validation"
}
{ "title": "Configuration", "href": "/core-concepts/configuration" }
]
},
{
Expand Down
Loading
Loading