schemantic 0.0.1-dev.13 copy "schemantic: ^0.0.1-dev.13" to clipboard
schemantic: ^0.0.1-dev.13 copied to clipboard

A general-purpose builder for generating type-safe data classes and JSON schemas from abstract definitions.

example/schemantic_example.dart

// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// ignore_for_file: strict_top_level_inference, always_declare_return_types, type_annotate_public_apis, unused_element

import 'package:schemantic/schemantic.dart';
part 'schemantic_example.g.dart';

@Schematic()
abstract class $Address {
  String get street;
  String get city;

  @AnyOf([int, String])
  get zipCode;
}

/// Define a schema using the @Schematic annotation.
/// This will generate a concrete [User] class with a static $schema field.
@Schematic()
abstract class $User {
  @StringField(minLength: 1, maxLength: 150, pattern: r'^[a-zA-Z\s]+$')
  String get name;
  @IntegerField(
    name: 'years_old',
    description: 'Age of the user',
    minimum: 0,
    maximum: 200,
  )
  int? get age;
  @Field(description: 'Is this user an admin?')
  bool get isAdmin;

  // Nested schema
  $Address? get address;
}

/// Define another schema for Products.
@Schematic()
abstract class $Product {
  String get id;
  String get name;
  double get price;
  List<String>? get tags;
}

void main() async {
  // 1. Create an instance using the generated class
  final address = Address(
    street: '123 Main St',
    city: 'Springfield',
    zipCode: AddressZipCode.int(62704),
  );

  final user = User(name: 'Alice', age: 30, isAdmin: true, address: address);

  print('--- Instance ---');
  print('Name: ${user.name}');
  print('Age: ${user.age}');
  print('Is Admin: ${user.isAdmin}');
  print('Address: ${user.address?.street}, ${user.address?.city}');

  // 2. Serialize to JSON
  final json = user.toJson();
  print('\n--- JSON Serialization ---');
  print(json);
  // Output: {name: Alice, age: 30, isAdmin: true, address: {street: 123 Main St, city: Springfield, zipCode: 62704}}

  // 3. Parse from JSON
  final parsed = User.$schema.parse({
    'name': 'Bob',
    'isAdmin': false,
    'address': {
      'street': '456 Elm St',
      'city': 'Shelbyville',
      'zipCode': '62705',
    },
  });
  print('\n--- JSON Parsing ---');
  print('Parsed Name: ${parsed.name}'); // Bob
  print('Parsed City: ${parsed.address?.city}'); // Shelbyville

  // 4. Access JSON Schema at runtime
  final schema = User.$schema.jsonSchema();
  print('\n--- JSON Schema ---');
  print(schema.toJson());

  // 5. Validation
  print('\n--- Validation ---');

  // Valid data
  final validData = <String, dynamic>{
    'name': 'Charlie',
    'isAdmin': true,
    'address': <String, dynamic>{
      'street': '789 Oak St',
      'city': 'Capital City',
      'zipCode': '62706',
    },
  };
  final validResult = await schema.validate(validData);
  if (validResult.isEmpty) {
    print('✅ Data is valid.');
  } else {
    print('❌ Validation failed: $validResult');
  }

  // Invalid data (missing required field 'isAdmin' and invalid nested field)
  final invalidData = <String, dynamic>{
    'name': 'Dave',
    'address': <String, dynamic>{
      // Missing required street, city, zipCode
    },
  };
  final invalidResult = await schema.validate(invalidData);
  if (invalidResult.isNotEmpty) {
    print('✅ Correctly detected invalid data:');
    for (final error in invalidResult) {
      print('  - $error');
    }
  }

  // 6. Dynamic Types (listSchema & mapSchema)
  print('\n--- Dynamic Types ---');

  // List of Strings
  final stringList = listSchema(
    User.$schema,
  ); // UserType is generated so it's fine
  final parsedList = stringList.parse([
    {'name': 'Alice', 'isAdmin': true},
    {'name': 'Bob', 'isAdmin': false},
  ]);
  print(
    'Parsed List: $parsedList',
  ); // [{name: Alice, isAdmin: true}, {name: Bob, isAdmin: false}]
  print('List Schema: ${stringList.jsonSchema().toJson()}');

  // Map of String -> User
  final scores = mapSchema(stringSchema(), User.$schema);
  final parsedScores = scores.parse({
    'Alice': {'name': 'Alice', 'isAdmin': true},
    'Bob': {'name': 'Bob', 'isAdmin': false},
  });
  print(
    'Parsed Map: $parsedScores',
  ); // {Alice: {name: Alice, isAdmin: true}, Bob: {name: Bob, isAdmin: false}}
  print('Map Schema: ${scores.jsonSchema().toJson()}');

  // 7. Another Schema Example (ProductSchema)
  print('\n--- ProductSchema Example ---');
  final productJson = {
    'id': 'p123',
    'name': 'Super Widget',
    'price': 19.99,
    'tags': ['gadget', 'new'],
  };
  final product = Product.$schema.parse(productJson);
  print('Product: ${product.name} costs \$${product.price}');
  print('Tags: ${product.tags}');

  // Validation check
  final productValidation = await Product.$schema.jsonSchema().validate({
    'id': 'p124',
    // Missing name and price
  });
  if (productValidation.isNotEmpty) {
    print('Validation correctly failed: $productValidation');
  }
}
1
likes
160
points
492
downloads

Publisher

verified publishergenkit.dev

Weekly Downloads

A general-purpose builder for generating type-safe data classes and JSON schemas from abstract definitions.

Repository (GitHub)
View/report issues
Contributing

Documentation

API reference

License

Apache-2.0 (license)

Dependencies

analyzer, build, code_builder, dart_style, json_schema_builder, source_gen

More

Packages that depend on schemantic