Skip to content
Draft
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
15 changes: 1 addition & 14 deletions packages/genui/lib/src/model/catalog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -271,25 +271,12 @@ class CatalogItemNotFoundException implements Exception {
}
}

class _CatalogItemComponentApi implements core.ComponentApi {
_CatalogItemComponentApi(this._item);
final CatalogItem _item;

@override
String get name => _item.name;

@override
Schema get schema => _item.dataSchema;
}

/// Builds the `a2ui_core` [core.Catalog] for [catalog], used when constructing
/// a [core.SurfaceModel] so `a2ui_core` lookups see real component metadata
/// instead of an empty stub.
@internal
core.Catalog<core.ComponentApi> coreCatalogFor(Catalog catalog) =>
core.Catalog<core.ComponentApi>(
id: catalog.effectiveCatalogId,
components: catalog.items
.map<core.ComponentApi>(_CatalogItemComponentApi.new)
.toList(growable: false),
components: catalog.items.toList(growable: false),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

While List<CatalogItem> is covariant and can be assigned to List<core.ComponentApi>, it is safer and more idiomatic to explicitly cast the iterable to ensure the runtime type of the list matches the expected List<core.ComponentApi>. This prevents potential runtime type errors if the receiving class performs operations that expect a List<core.ComponentApi> rather than a List<CatalogItem>.

Suggested change
components: catalog.items.toList(growable: false),
components: catalog.items.cast<core.ComponentApi>().toList(growable: false),

);
8 changes: 7 additions & 1 deletion packages/genui/lib/src/model/catalog_item.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.

import 'package:a2ui_core/a2ui_core.dart' as core;
import 'package:flutter/material.dart';
import 'package:json_schema_builder/json_schema_builder.dart';

Expand Down Expand Up @@ -81,7 +82,7 @@ final class CatalogItemContext {

/// Defines a UI layout type, its schema, and how to build its widget.
@immutable
final class CatalogItem {
final class CatalogItem implements core.ComponentApi {
/// Creates a new [CatalogItem].
const CatalogItem({
required this.name,
Expand All @@ -92,10 +93,15 @@ final class CatalogItem {
}) : _originalSchema = dataSchema;

/// The widget type name used in JSON, e.g., 'TextChatMessage'.
@override
final String name;

final Schema _originalSchema;

/// `core.ComponentApi` names this `schema`; genui exposes it as [dataSchema].
@override
Schema get schema => dataSchema;

/// The schema definition for this widget's data.
///
/// It should contain all of the component specific properties, but not the
Expand Down
9 changes: 9 additions & 0 deletions packages/genui/test/catalog_test.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.

import 'package:a2ui_core/a2ui_core.dart' as core;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:genui/genui.dart';
Expand Down Expand Up @@ -220,4 +221,12 @@ void main() {
expect(firstFunc.containsKey('parameters'), isTrue);
});
});

group('CatalogItem', () {
test('is a core.ComponentApi whose schema is its dataSchema', () {
final CatalogItem item = BasicCatalogItems.text;
expect(item, isA<core.ComponentApi>());
expect(item.schema.value, item.dataSchema.value);
});
});
}
Loading