Add or update a dart_mappable data model in lib/src/models/content/, including adding format validation, regenerating code, and adding tests. Use when adding a new content type or modifying an existing model's fields.
71
87%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Add or update a typed content model in this project. Follow the established conventions below as much as possible.
All data models live in the lib/src/models/content directory and
should roughly follow this general structure:
import 'package:dart_mappable/dart_mappable.dart';
import 'content_validation.dart';
part '<filename>.mapper.dart';
/// Doc comment: What this model represents and where it's loaded from.
///
/// Expected data format:
/// - `field_name`: Description and constraints of the expected value.
@MappableClass()
class ModelName with ModelNameMappable {
ModelName({
required this.fieldOne,
required this.fieldTwo,
this.optionalField,
}) {
// Validate all fields beyond their Dart type.
checkFormat(isNotBlank(fieldOne), 'field_one must be a non-empty string.');
// For optional fields, only validate when present:
if (optionalField case final optionalField?) {
checkFormat(isNotBlank(optionalField), 'optional_field must be a non-empty string.');
}
}
/// Each field should have a doc comment that follows Effective Dart.
final String fieldOne;
// Use `@MappableField` when the YAML key differs from the Dart field name.
@MappableField(key: 'field_two')
final String fieldTwo;
// Optional fields are nullable and not marked `required` in the constructor.
final String? optionalField;
// Every model must have this static factory. Use the generated mapper.
static ModelName fromJson(Map<String, Object?> json) => ModelNameMapper.fromMap(json);
}When adding a new data model,
consider checking the format of one or more existing models
in the lib/src/models/content/ directory.
content_validation.dart library and
use its helper functions to validate the contents of each field.part directive must point to <filename>.mapper.dart.
That part file is generated when running build_runner.<ClassName>Mappable.
That mixin is generated when running build_runner.fromJson factory delegates to <ClassName>Mapper.fromMap(json).@MappableField(key: 'yaml_key') when the YAML key uses
snake_case or otherwise differs from the camelCase Dart field name.@MappableEnum.MappingHook subclass in the same file.final.When users might make a mistake or a specific format is needed, fields should be validated in the constructor body, not just by Dart's type system.
Validation helpers are defined in
the lib/src/models/content/content_validation.dart library.
Some common validations include:
| Field type | Validation |
|---|---|
| Required string | checkFormat(isNotBlank(field), '...') |
| Optional string | if (field case final field?) checkFormat(isNotBlank(field), '...') |
| Absolute URL | checkFormat(isAbsoluteHttpUrl(field), '...') |
| Image asset path | checkFormat(looksLikeImageAssetPath(field), '...') |
| Hex color | checkFormat(isHexColor(field), '...') |
| Non-empty list | checkFormat(field.isNotEmpty, '...') |
As appropriate, multiple validations can be completed. Complete the less specific ones first, such as not being blank.
If you think any other validation is needed or might be helpful:
content_validation.dart library.content_validation.dart library.Run code generation to produce or update the .mapper.dart file:
dart run build_runner build --delete-conflicting-outputsAdd or update tests in test/models/content/content_models_test.dart.
Read the file to understand the existing testing patterns, import the new model, and add a test group following a similar pattern.
The test file already defines a few custom matchers. If needed, reuse them, don't unnecessarily redefine them.
_throwsMapperException:
For fields that are missing or have the wrong type._throwsValidationError:
For fields that exist but fail validation.Run tests to verify:
dart test test/models/content/content_models_test.dartRun analysis to catch any lint issues:
dart analyze lib/src/models/content/If you already are or want to use the data in a page, access the data using
the decodeJsonList and decodeJsonObject extension methods on BuildContext.
At the beginning of a page component's build method,
use the extension methods and store the data in a variable for reuse.
// For a list of items:
final items = context.decodeJsonList('page_name.data_key', ModelName.fromJson);
// For a single object:
final item = context.decodeJsonObject('page_name.data_key', ModelName.fromJson);The dot-notation path maps to the content directory structure. For example,
page_name.data_key resolves to content/page_name/data_key.yaml.
0438a63
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.