ResourceSchema.fromJson constructor
ResourceSchema.fromJson(})
direction is not read off json — a resource's direction always
comes from its panel. It defaults to PanelDirection.ltr so a directly
constructed resource (tests, the contract test, ResourceSchema.fake)
keeps working unchanged; PanelSchema.fromJson passes the panel's
parsed direction into every resource it builds. locales follows the
same rule, for the same reason: panel.locales is a panel-level fact,
not a per-resource one, so it is propagated here rather than read off
each resource's own JSON (which carries none).
Implementation
factory ResourceSchema.fromJson(
Map<String, dynamic> json,
String path, {
PanelDirection direction = PanelDirection.ltr,
List<String> locales = const [],
}) {
final sortNodes = objects(json, 'sorts', path);
final rawGroup = opt<String>(json, 'group');
return ResourceSchema(
key: req<String>(json, 'key', path),
labels: ResourceLabels.fromJson(
req<Map<String, dynamic>>(json, 'labels', path),
'$path.labels',
),
// object(), not opt(): an absent sub-object takes the documented default,
// but one that is present and not an object is a contract violation.
// Reading it as absent would silently deny every permission, blank the
// card, or switch search off.
permissions: ResourcePermissions.fromJson(
object(json, 'permissions', path) ?? const {},
),
recordKey: opt<String>(json, 'recordKey') ?? 'id',
card: CardLayout.fromJson(
object(json, 'card', path) ?? const {},
'$path.card',
),
search: ResourceSearch.fromJson(object(json, 'search', path) ?? const {}),
sorts: List.generate(
sortNodes.length,
(index) =>
ResourceSort.fromJson(sortNodes[index], '$path.sorts[$index]'),
),
filters: SchemaComponent.listFromJson(json, 'filters', path),
form: SchemaComponent.listFromJson(json, 'form', path),
infolist: SchemaComponent.listFromJson(json, 'infolist', path),
// Same rule as [direction] on this resource itself: propagated at parse
// time, not read off each relation's own JSON (which carries none).
relations: RelationDescriptor.listFromJson(
json,
path,
direction: direction,
),
group: rawGroup?.isEmpty ?? false ? null : rawGroup,
badge: switch (object(json, 'badge', path)) {
final badge? => ResourceBadge.fromJson(badge),
null => null,
},
direction: direction,
locales: locales,
);
}