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
10 changes: 9 additions & 1 deletion .agent/skills/genui-helper/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,12 @@ When creating a new UI component in `genui`:
- Example: https://dart.dev/tools/diagnostics/ambiguous_import
- To find out details of a specific analyzer lint message, use the following url format to look up the details:
- https://dart.dev/tools/linter-rules/<lint_rule_id>
- Example: https://dart.dev/tools/linter-rules/always_declare_return_types
- Example: https://dart.dev/tools/linter-rules/always_declare_return_types

## Code visibility

Make every code element as private as it can be. If tests need access, use the
language's test-visibility mechanism instead of making it public.
For example, in Dart, keep
the `_` prefix and annotate with `@visibleForTesting`.
Comment on lines +69 to +70

@gspencergoog gspencergoog Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think this will work, actually. Symbols starting with _ are private to the module. Marking them with @visibleForTesting won't export them to the test. You can only mark public functions as @visibleForTesting.

But I agree with the sentiment of keeping things private. For the skill, I'd word it like this:

Make every code element as private as it can be. If tests need access, design the API for testability with
dependency injection, abstraction, role interfaces, ports and adaptors, or other factoring improvements.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Oh, yes, this is standard source of confusion for me. Will send correction.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Correction: #1031


9 changes: 9 additions & 0 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Claude Code Context

Repository skills live in `.agent/skills/`, shared with the other agent tools
this repo supports. Claude Code only discovers skills under `.claude/skills/`,
so symlink the skills:

```bash
ln -s ../../.agent/skills/<name> .claude/skills/<name>
```
2 changes: 1 addition & 1 deletion coverage_baseline.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ packages/a2ui_core: 76.54
packages/genai_primitives: 100.00
packages/genui: 79.66
packages/genui_a2a: 91.37
packages/json_schema_builder: 79.09
packages/json_schema_builder: 81.93
tool/e2e: 100.00
tool/fix_copyright: 89.83
tool/release: 78.01
Expand Down
16 changes: 16 additions & 0 deletions packages/json_schema_builder/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# [json_schema_builder](https://pub.dev/packages/json_schema_builder) Change Log

## 0.1.7

- **Feature**: Add `Schema.validateSync`, a synchronous validation entry point
for schemas whose references all resolve without fetching. Validation itself
is now a synchronous core, and the existing `Schema.validate` is a thin
asynchronous wrapper around it that fetches the remote references it needs
into the `SchemaRegistry` up front, in parallel. Behavior of `validate` is
unchanged.
- **Feature**: Add `SchemaRegistry.resolveSync` and `SchemaRegistry.fetch`,
which split reference resolution from fetching, and
`SchemaRegistry.prefetchDependencies`, which fetches the schemas a schema
refers to in parallel so that it can then be validated synchronously.
- **Feature**: Export `SchemaFetchException` and the new
`SchemaResolutionRequiredException`, which `validateSync` throws when a
reference can only be resolved by fetching.

## 0.1.6

- **Feature**: Export `SchemaRegistry` to support managing schema references during component validation.
Expand Down
35 changes: 35 additions & 0 deletions packages/json_schema_builder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,38 @@ Future<void> main() async {
- List contains duplicate items at path #root["roles"]
- Additional property "extraField" is not allowed. at path #root["extraField"]
```

### Synchronous Validation

`validate` is asynchronous only because a `$ref` may point at a schema that has
to be fetched (loaded from source and parsed into a `Schema`). If your schema
has no such references — because they are inlined, or because you registered
every referenced schema up front — use `validateSync` instead and skip the
`Future`:

```dart
final errors = userProfileSchema.validateSync(validUser);
```

`validateSync` performs no I/O. If validation reaches a reference whose target
would have to be fetched, it throws a `SchemaResolutionRequiredException` naming
that target instead of skipping the reference, so a missing fetch can never turn
into a passing validation.

To fetch those schemas without validating anything, prepare the registry with
`prefetchDependencies`, which fetches everything the schema refers to, and
everything those schemas refer to in turn, in parallel:

```dart
final registry = SchemaRegistry();
await registry.prefetchDependencies(schema, baseUri: sourceUri);
final errors = schema.validateSync(
value,
sourceUri: sourceUri,
schemaRegistry: registry,
);
```

Note that a schema declaring a `$schema` meta-schema needs that meta-schema
resolved too, so pre-register it (or fetch it with one `validate` call) before
validating synchronously.
1 change: 1 addition & 0 deletions packages/json_schema_builder/lib/json_schema_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

export 'src/exceptions.dart';
export 'src/json_type.dart';
export 'src/schema/boolean_schema.dart';
export 'src/schema/integer_schema.dart';
Expand Down
25 changes: 25 additions & 0 deletions packages/json_schema_builder/lib/src/exceptions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,28 @@ class SchemaFetchException implements Exception {
return message;
}
}

/// Thrown by the synchronous validation path when a reference can only be
/// resolved by fetching a schema that is not in the `SchemaRegistry` yet.
///
/// Synchronous validation never performs I/O, so it cannot fetch the schema
/// itself. Rather than treating the unresolved subschema as unconstrained,
/// which would silently turn a missing fetch into a passing validation, it
/// throws this exception.
///
/// To fix it, either bring the schema at [uri] into the registry before
/// validating (with `SchemaRegistry.addSchema` or
/// `SchemaRegistry.prefetchDependencies`), or use the asynchronous `validate`
/// method, which fetches the remote schemas it needs before validating.
class SchemaResolutionRequiredException implements Exception {
/// The URI of the schema that would have to be fetched, without any fragment.
final Uri uri;

SchemaResolutionRequiredException(this.uri);

@override
String toString() =>
'Synchronous validation requires the schema at $uri, which is not '
'registered. Add it to the SchemaRegistry, or use the asynchronous '
'Schema.validate to fetch it.';
}
Loading
Loading